| // Copyright 2016 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_ASH_NOTE_TAKING_HELPER_H_ |
| #define CHROME_BROWSER_ASH_NOTE_TAKING_HELPER_H_ |
| |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <vector> |
| |
| #include "ash/components/arc/mojom/intent_helper.mojom-forward.h" |
| #include "base/functional/callback.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/observer_list.h" |
| #include "base/scoped_multi_source_observation.h" |
| #include "base/scoped_observation.h" |
| #include "chrome/browser/ash/arc/session/arc_session_manager_observer.h" |
| #include "chrome/browser/ash/lock_screen_apps/lock_screen_apps.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/browser/profiles/profile_manager_observer.h" |
| #include "components/arc/intent_helper/arc_intent_helper_bridge.h" |
| #include "components/arc/intent_helper/arc_intent_helper_observer.h" |
| #include "components/services/app_service/public/cpp/app_registry_cache.h" |
| |
| class Profile; |
| |
| namespace apps { |
| class AppUpdate; |
| } |
| |
| namespace content { |
| class BrowserContext; |
| } // namespace content |
| |
| namespace extensions { |
| class Extension; |
| namespace api { |
| namespace app_runtime { |
| struct ActionData; |
| } // namespace app_runtime |
| } // namespace api |
| } // namespace extensions |
| |
| namespace ash { |
| |
| class NoteTakingControllerClient; |
| |
| // Information about an installed note-taking app. |
| struct NoteTakingAppInfo { |
| // Application name to display to user. |
| std::string name; |
| |
| // Either an extension ID (in the case of a Chrome app) or a package name (in |
| // the case of an Android app) or a web app ID (in the case of a web app). |
| std::string app_id; |
| |
| // True if this is the preferred note-taking app. |
| bool preferred; |
| |
| // Whether the app supports use on the Chrome OS lock screen. |
| LockScreenAppSupport lock_screen_support; |
| }; |
| |
| // Singleton class used to launch a note-taking app. |
| class NoteTakingHelper : public arc::ArcIntentHelperObserver, |
| public arc::ArcSessionManagerObserver, |
| public apps::AppRegistryCache::Observer, |
| public ProfileManagerObserver { |
| public: |
| // Interface for observing changes to the list of available apps. |
| class Observer { |
| public: |
| virtual ~Observer() = default; |
| |
| // Called when the list of available apps that will be returned by |
| // GetAvailableApps() changes or when |play_store_enabled_| changes state. |
| virtual void OnAvailableNoteTakingAppsUpdated() = 0; |
| |
| // Called when the preferred note taking app (or its properties) in |
| // |profile| is updated. |
| virtual void OnPreferredNoteTakingAppUpdated(Profile* profile) = 0; |
| }; |
| |
| // Describes the result of an attempt to launch a note-taking app. Values must |
| // not be renumbered, as this is used by histogram metrics. |
| enum class LaunchResult { |
| // A Chrome app was launched successfully. |
| CHROME_SUCCESS = 0, |
| // The requested Chrome app was unavailable. |
| CHROME_APP_MISSING = 1, |
| // An Android app was launched successfully. |
| ANDROID_SUCCESS = 2, |
| // An Android app couldn't be launched due to the profile not being allowed |
| // to use ARC. |
| ANDROID_NOT_SUPPORTED_BY_PROFILE = 3, |
| // An Android app couldn't be launched due to ARC not running. |
| ANDROID_NOT_RUNNING = 4, |
| // Removed: An Android app couldn't be launched due to a failure to convert |
| // the supplied path to an ARC URL. |
| // ANDROID_FAILED_TO_CONVERT_PATH = 5, |
| // No attempt was made due to a preferred app not being specified. |
| NO_APP_SPECIFIED = 6, |
| // No Android or Chrome apps were available. |
| NO_APPS_AVAILABLE = 7, |
| // A web app was launched successfully. |
| WEB_APP_SUCCESS = 8, |
| // The requested web app was unavailable. |
| WEB_APP_MISSING = 9, |
| // Unable to find an internal display. |
| NO_INTERNAL_DISPLAY_FOUND = 10, |
| // This value must remain last and should be incremented when a new reason |
| // is inserted. |
| MAX = 11, |
| }; |
| |
| // Callback used to launch a Chrome app. |
| using LaunchChromeAppCallback = |
| base::RepeatingCallback<void(content::BrowserContext* context, |
| const extensions::Extension*, |
| extensions::api::app_runtime::ActionData)>; |
| |
| // Intent action used to launch Android apps. |
| static const char kIntentAction[]; |
| |
| // Extension IDs for the development and released versions of the Google Keep |
| // Chrome app. |
| static const char kDevKeepExtensionId[]; |
| static const char kProdKeepExtensionId[]; |
| // Web app IDs for testing and development versions of note-taking web apps. |
| static const char kNoteTakingWebAppIdTest[]; |
| static const char kNoteTakingWebAppIdDev[]; |
| |
| // Names of histograms. |
| static const char kPreferredLaunchResultHistogramName[]; |
| static const char kDefaultLaunchResultHistogramName[]; |
| |
| static void Initialize(); |
| static void Shutdown(); |
| static NoteTakingHelper* Get(); |
| |
| NoteTakingHelper(const NoteTakingHelper&) = delete; |
| NoteTakingHelper& operator=(const NoteTakingHelper&) = delete; |
| |
| bool play_store_enabled() const { return play_store_enabled_; } |
| bool android_apps_received() const { return android_apps_received_; } |
| |
| void set_launch_chrome_app_callback_for_test( |
| const LaunchChromeAppCallback& callback) { |
| launch_chrome_app_callback_ = callback; |
| } |
| |
| // Adds or removes an observer. |
| void AddObserver(Observer* observer); |
| void RemoveObserver(Observer* observer); |
| |
| // Inform the NoteTakingHelper that the given app was updated. May trigger |
| // notifications to observers. |
| void NotifyAppUpdated(Profile* profile, const std::string& app_id); |
| |
| // Returns a list of available note-taking apps, in the order they should be |
| // shown in UI. |
| std::vector<NoteTakingAppInfo> GetAvailableApps(Profile* profile); |
| |
| // Returns the ID of the preferred note-taking app. Empty if uninstalled or |
| // not set. |
| std::string GetPreferredAppId(Profile* profile); |
| |
| // Sets the preferred note-taking app. |app_id| is a value from a |
| // NoteTakingAppInfo object. |
| void SetPreferredApp(Profile* profile, const std::string& app_id); |
| |
| // Sets whether the preferred note taking app is allowed to run on the lock |
| // screen. |
| // Returns whether the app status changed. |
| bool SetPreferredAppEnabledOnLockScreen(Profile* profile, bool enabled); |
| |
| // Returns true if an app that can be used to take notes is available. UI |
| // surfaces that call LaunchAppForNewNote() should be hidden otherwise. |
| bool IsAppAvailable(Profile* profile); |
| |
| // Launches the note-taking app to create a new note. IsAppAvailable() must |
| // be called first. |
| void LaunchAppForNewNote(Profile* profile); |
| |
| // arc::ArcIntentHelperObserver: |
| void OnIntentFiltersUpdated( |
| const std::optional<std::string>& package_name) override; |
| |
| // arc::ArcSessionManagerObserver: |
| void OnArcPlayStoreEnabledChanged(bool enabled) override; |
| |
| // ProfileManagerObserver: |
| void OnProfileAdded(Profile* profile) override; |
| void OnProfileManagerDestroying() override; |
| |
| NoteTakingControllerClient* GetNoteTakingControllerClientForTesting() { |
| return note_taking_controller_client_.get(); |
| } |
| |
| private: |
| NoteTakingHelper(); |
| ~NoteTakingHelper() override; |
| |
| // Queries and returns the app IDs of note-taking Chrome/web apps that are |
| // installed, enabled, and allowed for |profile|. |
| std::vector<std::string> GetNoteTakingAppIds(Profile* profile) const; |
| |
| // Requests a list of Android note-taking apps from ARC. |
| void UpdateAndroidApps(); |
| |
| // Handles ARC's response to an earlier UpdateAndroidApps() call. |
| void OnGotAndroidApps(std::vector<arc::mojom::IntentHandlerInfoPtr> handlers); |
| |
| // Helper method that launches |app_id| (either an Android package name or a |
| // Chrome extension ID) to create a new note. Returns the attempt's result. |
| LaunchResult LaunchAppInternal(Profile* profile, const std::string& app_id); |
| |
| // apps::AppRegistryCache::Observer |
| void OnAppUpdate(const apps::AppUpdate& update) override; |
| void OnAppRegistryCacheWillBeDestroyed( |
| apps::AppRegistryCache* cache) override; |
| |
| // True iff Play Store is enabled (i.e. per the checkbox on the settings |
| // page). Note that ARC may not be fully started yet when this is true, but it |
| // is expected to start eventually. Similarly, ARC may not be fully shut down |
| // yet when this is false, but will be eventually. |
| bool play_store_enabled_ = false; |
| |
| // This is set to true after |android_apps_| is updated. |
| bool android_apps_received_ = false; |
| |
| // Callback used to launch Chrome apps. Can be overridden for tests. |
| LaunchChromeAppCallback launch_chrome_app_callback_; |
| |
| // IDs of allowed (but not necessarily installed) Chrome apps or web apps for |
| // note-taking, in the order in which they're chosen if the user hasn't |
| // expressed a preference. Explicitly set by command-line and a default |
| // hard-coded list. |
| std::vector<std::string> force_allowed_app_ids_; |
| |
| // Cached information about available Android note-taking apps. |
| std::vector<NoteTakingAppInfo> android_apps_; |
| |
| // Observes ArcIntentHelper for changes to Android intent filters. |
| // TODO(crbug.com/40228788): Remove when App Service publishes Android Apps |
| // with note-taking intent. |
| base::ScopedMultiSourceObservation<arc::ArcIntentHelperBridge, |
| arc::ArcIntentHelperObserver> |
| arc_intent_helper_observations_{this}; |
| |
| // Obseves App Registry for all profiles with an App Registry. |
| base::ScopedMultiSourceObservation<apps::AppRegistryCache, |
| apps::AppRegistryCache::Observer> |
| app_registry_observations_{this}; |
| |
| base::ScopedObservation<ProfileManager, ProfileManagerObserver> |
| profile_manager_observation_{this}; |
| |
| base::ObserverList<Observer>::Unchecked observers_; |
| |
| std::unique_ptr<NoteTakingControllerClient> note_taking_controller_client_; |
| |
| base::WeakPtrFactory<NoteTakingHelper> weak_ptr_factory_{this}; |
| }; |
| |
| } // namespace ash |
| |
| #endif // CHROME_BROWSER_ASH_NOTE_TAKING_HELPER_H_ |