chromium/chromeos/ash/components/throttle/window_throttle_observer_base.cc

// 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