chromium/chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_UI_ASH_KEYBOARD_CHROME_KEYBOARD_CONTROLLER_CLIENT_H_
#define CHROME_BROWSER_UI_ASH_KEYBOARD_CHROME_KEYBOARD_CONTROLLER_CLIENT_H_

#include <memory>
#include <optional>
#include <set>
#include <vector>

#include "ash/public/cpp/keyboard/keyboard_config.h"
#include "ash/public/cpp/keyboard/keyboard_controller.h"
#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/session_manager/core/session_manager_observer.h"
#include "url/gurl.h"

class ChromeKeyboardWebContents;
class Profile;

namespace aura {
class Window;
}

// This class implements KeyboardControllerObserver and makes calls
// into the KeyboardController service. It also observes keyboard prefs
// and enables or disables the keyboard accordingly.
class ChromeKeyboardControllerClient
    : public ash::KeyboardControllerObserver,
      public session_manager::SessionManagerObserver {
 public:
  // Convenience observer allowing UI classes to observe the global instance of
  // this class.
  class Observer : public base::CheckedObserver {
   public:
    ~Observer() override = default;

    // Forwards the 'OnKeyboardVisibilityChanged' observer method.
    // This is used by oobe and login to adjust the UI.
    virtual void OnKeyboardVisibilityChanged(bool visible) {}

    virtual void OnKeyboardVisibleBoundsChanged(
        const gfx::Rect& screen_bounds) {}

    // Forwards the 'OnKeyboardOccludedBoundsChanged' observer method.
    // This is used to update the insets of browser and app windows when the
    // keyboard is shown.
    virtual void OnKeyboardOccludedBoundsChanged(
        const gfx::Rect& screen_bounds) {}

    // Notifies observers when the keyboard content (i.e. the extension) has
    // loaded. Note: if the content is already loaded when the observer is
    // added, this will not be triggered, but see is_keyboard_loaded().
    virtual void OnKeyboardLoaded() {}

    // Forwards the 'OnKeyboardEnabledChanged' observer method.
    virtual void OnKeyboardEnabledChanged(bool enabled) {}
  };

  // Creates the singleton instance for chrome or browser tests.
  // |Init| needs to be called after creation.
  static std::unique_ptr<ChromeKeyboardControllerClient> Create();

  // Creates the singleton instance for unit tests where there is no
  // SessionManager. Prefs will not be observed or affect the enabled state.
  // |Init| needs to be called after creation.
  static std::unique_ptr<ChromeKeyboardControllerClient> CreateForTest();

  // Static getter. The single instance must be instantiated first.
  static ChromeKeyboardControllerClient* Get();

  // Used in tests to determine whether this has been instantiated.
  static bool HasInstance();

  ChromeKeyboardControllerClient(const ChromeKeyboardControllerClient&) =
      delete;
  ChromeKeyboardControllerClient& operator=(
      const ChromeKeyboardControllerClient&) = delete;

  ~ChromeKeyboardControllerClient() override;

  // Called after ash::Shell is created.
  void Init(ash::KeyboardController* keyboard_controller);

  // Called before Shell or the primary profile is destroyed.
  void Shutdown();

  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);

  // In Classic Ash, notifies this that the contents have loaded, triggering
  // OnKeyboardLoaded.
  void NotifyKeyboardLoaded();

  // Returns the cached KeyboardConfig value.
  keyboard::KeyboardConfig GetKeyboardConfig();

  // Sets the new keyboard configuration and updates the cached config.
  void SetKeyboardConfig(const keyboard::KeyboardConfig& config);

  // Returns the current enabled state. Call this after Set/ClearEnableFlag to
  // get the updated enabled state.
  bool GetKeyboardEnabled();

  // Sets/clears the privided keyboard enable state.
  void SetEnableFlag(const keyboard::KeyboardEnableFlag& flag);
  void ClearEnableFlag(const keyboard::KeyboardEnableFlag& flag);

  // Returns whether |flag| has been set.
  bool IsEnableFlagSet(const keyboard::KeyboardEnableFlag& flag);

  // Calls forwarded to ash::KeyboardController.
  void ReloadKeyboardIfNeeded();
  void RebuildKeyboardIfEnabled();
  void ShowKeyboard();
  void HideKeyboard(ash::HideReason reason);
  void SetContainerType(keyboard::ContainerType container_type,
                        const gfx::Rect& target_bounds,
                        base::OnceCallback<void(bool)> callback);
  void SetKeyboardLocked(bool locked);
  void SetOccludedBounds(const std::vector<gfx::Rect>& bounds);
  void SetHitTestBounds(const std::vector<gfx::Rect>& bounds);
  bool SetAreaToRemainOnScreen(const gfx::Rect& bounds);
  void SetDraggableArea(const gfx::Rect& bounds);
  bool SetWindowBoundsInScreen(const gfx::Rect& bounds_in_screen);
  void SetKeyboardConfigFromPref(bool enabled);

  // Returns true if overscroll is enabled by the config or command line.
  bool IsKeyboardOverscrollEnabled();

  // Returns the URL to use for the virtual keyboard.
  GURL GetVirtualKeyboardUrl();

  // Returns the keyboard window, or null if the window has not been created.
  aura::Window* GetKeyboardWindow() const;

  bool is_keyboard_enabled() { return is_keyboard_enabled_; }
  bool is_keyboard_loaded() { return is_keyboard_loaded_; }
  bool is_keyboard_visible() { return is_keyboard_visible_; }

  void set_keyboard_enabled_for_test(bool enabled) {
    is_keyboard_enabled_ = enabled;
  }
  void set_keyboard_visible_for_test(bool visible) {
    is_keyboard_visible_ = visible;
  }
  void set_profile_for_test(Profile* profile) { profile_for_test_ = profile; }
  void set_virtual_keyboard_url_for_test(const GURL& url) {
    virtual_keyboard_url_for_test_ = url;
  }

 private:
  ChromeKeyboardControllerClient();

  // Called from Create() to observer session_SessionManager and initialize
  // |pref_change_registrar_| once the session starts.
  void InitializePrefObserver();

  // ash::KeyboardControllerObserver:
  void OnKeyboardEnableFlagsChanged(
      const std::set<keyboard::KeyboardEnableFlag>& flags) override;
  void OnKeyboardEnabledChanged(bool enabled) override;
  void OnKeyboardConfigChanged(const keyboard::KeyboardConfig& config) override;
  void OnKeyboardVisibilityChanged(bool visible) override;
  void OnKeyboardVisibleBoundsChanged(const gfx::Rect& screen_bounds) override;
  void OnKeyboardOccludedBoundsChanged(const gfx::Rect& screen_bounds) override;
  void OnLoadKeyboardContentsRequested() override;
  void OnKeyboardUIDestroyed() override;

  // Called when the keyboard contents have loaded. Notifies observers.
  void OnKeyboardContentsLoaded();

  // session_manager::SessionManagerObserver:
  void OnSessionStateChanged() override;

  // Sets whether the virtual keyboard is enabled from prefs.
  void SetTouchKeyboardEnabledFromPrefs();

  // Sets whether smart visibility is enabled from prefs.
  void SetSmartVisibilityFromPrefs();

  // Returns either the test profile or the active user profile.
  Profile* GetProfile();

  gfx::Rect BoundsFromScreen(const gfx::Rect& screen_bounds);

  std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;

  raw_ptr<ash::KeyboardController> keyboard_controller_ = nullptr;

  // Set when the WS is used and OnLoadKeyboardContentsRequested is called.
  std::unique_ptr<ChromeKeyboardWebContents> keyboard_contents_;

  // Cached copy of the latest config provided by KeyboardController.
  std::optional<keyboard::KeyboardConfig> cached_keyboard_config_;

  // Cached copy of the active enabled flags provided by KeyboardController.
  std::set<keyboard::KeyboardEnableFlag> keyboard_enable_flags_;

  // Tracks the enabled state of the keyboard.
  bool is_keyboard_enabled_ = false;

  // Tracks when the keyboard content has loaded.
  bool is_keyboard_loaded_ = false;

  // Tracks the visible state of the keyboard.
  bool is_keyboard_visible_ = false;

  base::ObserverList<Observer> observers_;

  raw_ptr<Profile> profile_for_test_ = nullptr;
  GURL virtual_keyboard_url_for_test_;

  base::WeakPtrFactory<ChromeKeyboardControllerClient> weak_ptr_factory_{this};
};

#endif  // CHROME_BROWSER_UI_ASH_KEYBOARD_CHROME_KEYBOARD_CONTROLLER_CLIENT_H_