1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/chromeos/window_throttle_observer_base.h"
6 
7 #include "ash/public/cpp/shell_window_ids.h"
8 #include "components/exo/wm_helper.h"
9 #include "ui/aura/window.h"
10 #include "ui/wm/public/activation_change_observer.h"
11 
12 namespace chromeos {
13 namespace {
14 
15 // Returns true if the window is in the app list window container.
IsAppListWindow(const aura::Window * window)16 bool IsAppListWindow(const aura::Window* window) {
17   if (!window)
18     return false;
19 
20   const aura::Window* parent = window->parent();
21   return parent &&
22          parent->id() == ash::ShellWindowId::kShellWindowId_AppListContainer;
23 }
24 
25 // Returns true if this window activation should be ignored (app list
26 // opening/closing), or false if it should be processed.
ShouldIgnoreWindowActivation(wm::ActivationChangeObserver::ActivationReason reason,aura::Window * gained_active,aura::Window * lost_active)27 bool ShouldIgnoreWindowActivation(
28     wm::ActivationChangeObserver::ActivationReason reason,
29     aura::Window* gained_active,
30     aura::Window* lost_active) {
31   // The current active window defines whether the instance should be
32   // throttled or not i.e. if it's a native window then throttle Android, if
33   // it's an Android window then unthrottle it.
34   //
35   // However, the app list needs to be handled differently. The app list is
36   // deemed as an temporary overlay over the user's main window for browsing
37   // through or selecting an app. Consequently, if the app list is brought
38   // over a Chrome window then IsAppListWindow(gained_active) is true and this
39   // event is ignored. The instance continues to be throttled. Once the app
40   // list is closed then IsAppListWindow(lost_active) is true and the instance
41   // continues to be throttled. Similarly, if the app list is brought over an
42   // Android window, the instance continues to be unthrottled.
43   //
44   // On launching an app from the app list on Chrome OS the following events
45   // happen -
46   //
47   // - When an Android app icon is clicked the instance is unthrottled. This
48   // logic resides in |LaunchAppWithIntent| in
49   // src/chrome/browser/ui/app_list/arc/arc_app_utils.cc.
50   //
51   // - Between the time the app opens there is a narrow slice of time where
52   // this callback is triggered with |lost_active| equal to the app list
53   // window and the gained active possibly a native window. Without the check
54   // below the instance will be throttled again, further delaying the app
55   // launch. If the app was a native one then the instance was throttled
56   // anyway.
57   if (IsAppListWindow(lost_active) || IsAppListWindow(gained_active))
58     return true;
59   return false;
60 }
61 
62 }  // namespace
63 
WindowThrottleObserverBase(ThrottleObserver::PriorityLevel level,std::string name)64 WindowThrottleObserverBase::WindowThrottleObserverBase(
65     ThrottleObserver::PriorityLevel level,
66     std::string name)
67     : ThrottleObserver(level, name) {}
68 
StartObserving(content::BrowserContext * context,const ObserverStateChangedCallback & callback)69 void WindowThrottleObserverBase::StartObserving(
70     content::BrowserContext* context,
71     const ObserverStateChangedCallback& callback) {
72   ThrottleObserver::StartObserving(context, callback);
73   if (!exo::WMHelper::HasInstance())  // for unit testing
74     return;
75   exo::WMHelper::GetInstance()->AddActivationObserver(this);
76 }
77 
StopObserving()78 void WindowThrottleObserverBase::StopObserving() {
79   ThrottleObserver::StopObserving();
80   if (!exo::WMHelper::HasInstance())
81     return;
82   exo::WMHelper::GetInstance()->RemoveActivationObserver(this);
83 }
84 
OnWindowActivated(ActivationReason reason,aura::Window * gained_active,aura::Window * lost_active)85 void WindowThrottleObserverBase::OnWindowActivated(ActivationReason reason,
86                                                    aura::Window* gained_active,
87                                                    aura::Window* lost_active) {
88   if (ShouldIgnoreWindowActivation(reason, gained_active, lost_active))
89     return;
90   SetActive(ProcessWindowActivation(reason, gained_active, lost_active));
91 }
92 
93 }  // namespace chromeos
94