// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ash/components/throttle/window_throttle_observer_base.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "components/exo/wm_helper.h"
#include "ui/aura/window.h"
#include "ui/wm/public/activation_change_observer.h"
namespace ash {
namespace {
// Returns true if the window is in the app list window container.
bool IsAppListWindow(const aura::Window* window) {
if (!window)
return false;
const aura::Window* parent = window->parent();
return parent &&
parent->GetId() == ShellWindowId::kShellWindowId_AppListContainer;
}
// Returns true if this window activation should be ignored (app list
// opening/closing), or false if it should be processed.
bool ShouldIgnoreWindowActivation(
wm::ActivationChangeObserver::ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active) {
// The current active window defines whether the instance should be
// throttled or not i.e. if it's a native window then throttle Android, if
// it's an Android window then unthrottle it.
//
// However, the app list needs to be handled differently. The app list is
// deemed as an temporary overlay over the user's main window for browsing
// through or selecting an app. Consequently, if the app list is brought
// over a Chrome window then IsAppListWindow(gained_active) is true and this
// event is ignored. The instance continues to be throttled. Once the app
// list is closed then IsAppListWindow(lost_active) is true and the instance
// continues to be throttled. Similarly, if the app list is brought over an
// Android window, the instance continues to be unthrottled.
//
// On launching an app from the app list on Chrome OS the following events
// happen -
//
// - When an Android app icon is clicked the instance is unthrottled. This
// logic resides in |LaunchAppWithIntent| in
// src/chrome/browser/ash/app_list/arc/arc_app_utils.cc.
//
// - Between the time the app opens there is a narrow slice of time where
// this callback is triggered with |lost_active| equal to the app list
// window and the gained active possibly a native window. Without the check
// below the instance will be throttled again, further delaying the app
// launch. If the app was a native one then the instance was throttled
// anyway.
if (IsAppListWindow(lost_active) || IsAppListWindow(gained_active))
return true;
return false;
}
} // namespace
WindowThrottleObserverBase::WindowThrottleObserverBase(const std::string& name)
: ThrottleObserver(name) {}
void WindowThrottleObserverBase::StartObserving(
content::BrowserContext* context,
const ObserverStateChangedCallback& callback) {
ThrottleObserver::StartObserving(context, callback);
if (!exo::WMHelper::HasInstance()) // for unit testing
return;
exo::WMHelper::GetInstance()->AddActivationObserver(this);
}
void WindowThrottleObserverBase::StopObserving() {
ThrottleObserver::StopObserving();
if (!exo::WMHelper::HasInstance())
return;
exo::WMHelper::GetInstance()->RemoveActivationObserver(this);
}
void WindowThrottleObserverBase::OnWindowActivated(ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active) {
if (ShouldIgnoreWindowActivation(reason, gained_active, lost_active))
return;
SetActive(ProcessWindowActivation(reason, gained_active, lost_active));
}
} // namespace ash