1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
// Copyright 2022 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_EXTENSIONS_API_SIDE_PANEL_SIDE_PANEL_SERVICE_H_
#define CHROME_BROWSER_EXTENSIONS_API_SIDE_PANEL_SIDE_PANEL_SERVICE_H_
#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/scoped_observation.h"
#include "base/types/expected.h"
#include "chrome/common/extensions/api/side_panel.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/common/extension_id.h"
namespace extensions {
// The single responsibility of this service is to be the source of truth for
// side panel options. Extensions can interact with this service using the API
// and side panel UI updates can rely on the response of GetOptions(tab_id).
class SidePanelService : public BrowserContextKeyedAPI,
public ExtensionRegistryObserver {
public:
class Observer : public base::CheckedObserver {
public:
virtual void OnPanelOptionsChanged(
const ExtensionId& extension_id,
const api::side_panel::PanelOptions& updated_options) = 0;
virtual void OnSidePanelServiceShutdown() = 0;
};
explicit SidePanelService(content::BrowserContext* context);
SidePanelService(const SidePanelService&) = delete;
SidePanelService& operator=(const SidePanelService&) = delete;
~SidePanelService() override;
// Convenience method to get the SidePanelService for a profile.
static SidePanelService* Get(content::BrowserContext* context);
// BrowserContextKeyedAPI implementation.
static BrowserContextKeyedAPIFactory<SidePanelService>* GetFactoryInstance();
using TabId = int;
// Returns if there is an action to toggle the side panel for the given
// `extension` and `tab_id`.
bool HasSidePanelActionForTab(const Extension& extension, TabId tab_id);
// Returns if there is an action to toggle the side panel from the extension
// context menu for the given `extension` and `tab_id`.
bool HasSidePanelContextMenuActionForTab(const Extension& extension,
TabId tab_id);
// Get options for `tab_id`. Options are loaded in order first from service
// storage, manifest, or an empty object will be returned, if they're unset.
api::side_panel::PanelOptions GetOptions(const Extension& extension,
std::optional<TabId> tab_id);
// Get options that were set for `tab_id`. If no options were specifically
// set, returns an empty object instead of falling back to default options.
api::side_panel::PanelOptions GetSpecificOptionsForTab(
const Extension& extension,
TabId tab_id);
// Set options for tab_id if specified. Otherwise set default options.
void SetOptions(const Extension& extension,
api::side_panel::PanelOptions set_options);
// Determine if panel options have been set for extension id. Used in tests.
bool HasExtensionPanelOptionsForTest(const ExtensionId& id);
// Returns whether the extension will open its side panel entry when its icon
// in the toolbar is clicked.
bool OpenSidePanelOnIconClick(const ExtensionId& extension_id);
// Updates whether the extension will open its side panel entry when its icon
// in the toolbar is clicked.
void SetOpenSidePanelOnIconClick(const ExtensionId& extension_id,
bool open_side_panel_on_icon_click);
// Opens the `extension`'s side panel for the specified `tab_id` and profile
// specified by `context`. Handles properly determining if the side panel to
// be opened is a global or contextual panel. `include_incognito_information`
// indicates whether the registry should allow crossing incognito contexts
// when looking up `tab_id`. If `window_id` is specified, checks that the
// given `tab_id` belongs to the `window_id`. Returns true on success; returns
// an error string on failure.
// TODO(crbug.com/40064601): Return an enum here to indicate if the
// panel was newly-opened vs already-opened in order to support waiting for
// the panel to open?
base::expected<bool, std::string> OpenSidePanelForTab(
const Extension& extension,
content::BrowserContext* context,
int tab_id,
std::optional<int> window_id,
bool include_incognito_information);
// Opens the `extension`'s side panel for the specified `window_id` and
// profile specified by `context`. This is only valid if the extension has a
// registered global side panel. This will not override any contextual panels
// in the window. `include_incognito_information` indicates whether the
// registry should allow crossing incognito contexts when looking up `tab_id`.
// Returns true on success; returns an error string on failure.
// TODO(crbug.com/40064601): Return an enum here to indicate if the
// panel was newly-opened vs already-opened in order to support waiting for
// the panel to open?
base::expected<bool, std::string> OpenSidePanelForWindow(
const Extension& extension,
content::BrowserContext* context,
int window_id,
bool include_incognito_information);
// Adds or removes observers.
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
private:
friend class BrowserContextKeyedAPIFactory<SidePanelService>;
const raw_ptr<content::BrowserContext> browser_context_;
// BrowserContextKeyedAPI implementation.
static const char* service_name() { return "SidePanelService"; }
static const bool kServiceRedirectedInIncognito = true;
static const bool kServiceIsNULLWhileTesting = true;
// Returns if there is an extension side panel for `tab_id`.
bool HasSidePanelAvailableForTab(const Extension& extension, TabId tab_id);
// Remove extension id and associated options from `panels_`.
void RemoveExtensionOptions(const ExtensionId& id);
// ExtensionRegistry:
void OnExtensionUnloaded(content::BrowserContext* browser_context,
const Extension* extension,
UnloadedExtensionReason reason) override;
// ExtensionRegistry:
void OnExtensionUninstalled(content::BrowserContext* browser_context,
const Extension* extension,
UninstallReason reason) override;
// KeyedService implementation.
void Shutdown() override;
// The associated observers.
base::ObserverList<Observer> observers_;
// ExtensionRegistry observer.
base::ScopedObservation<extensions::ExtensionRegistry,
extensions::ExtensionRegistryObserver>
extension_registry_observation_{this};
// Extension and tab panel options.
using TabPanelOptions = base::flat_map<TabId, api::side_panel::PanelOptions>;
using ExtensionPanelOptions = base::flat_map<ExtensionId, TabPanelOptions>;
ExtensionPanelOptions panels_;
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_SIDE_PANEL_SIDE_PANEL_SERVICE_H_
|