File: web_app_tab_helper.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (238 lines) | stat: -rw-r--r-- 10,305 bytes parent folder | download | duplicates (5)
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
// 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_WEB_APPLICATIONS_WEB_APP_TAB_HELPER_H_
#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_TAB_HELPER_H_

#include <optional>
#include <vector>

#include "base/callback_list.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/unguessable_token.h"
#include "chrome/browser/web_applications/web_app_install_manager.h"
#include "chrome/browser/web_applications/web_app_install_manager_observer.h"
#include "components/tabs/public/tab_interface.h"
#include "components/webapps/common/web_app_id.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"

namespace content {
class WebContents;
}

namespace webapps {
class LaunchQueue;
}

namespace web_app {

class WebAppProvider;

// Per-tab web app helper. Allows to associate a tab (web page) with a web app.
class WebAppTabHelper : public content::WebContentsUserData<WebAppTabHelper>,
                        public content::WebContentsObserver,
                        public WebAppInstallManagerObserver {
 public:
  // `contents` can be different from `tab->GetContents()` during tab discard.
  // TODO(https://crbug.com/347770670): This method can be simplified to not
  // take `contents`.
  static void Create(tabs::TabInterface* tab, content::WebContents* contents);

  // Retrieves the WebAppTabHelper's app ID off |web_contents|, returns
  // nullptr if there is no tab helper or app ID.
  static const webapps::AppId* GetAppId(
      const content::WebContents* web_contents);

#if BUILDFLAG(IS_MAC)
  // Like the above method, but also checks if notification attribution should
  // apply to the app in the web contents. This checks the base::Feature as well
  // as makes sure the app is installed.
  static std::optional<webapps::AppId> GetAppIdForNotificationAttribution(
      content::WebContents* web_contents);
#endif

  WebAppTabHelper(tabs::TabInterface* tab, content::WebContents* contents);
  WebAppTabHelper(const WebAppTabHelper&) = delete;
  WebAppTabHelper& operator=(const WebAppTabHelper&) = delete;
  ~WebAppTabHelper() override;

  // Sets the app id for this web contents. Ideally the app id would always be
  // equal to the id of whatever app the last committed primary main frame URL
  // is in scope for (and WebAppTabHelper resets it to that any time a
  // navigation commits), but for legacy reasons sometimes the app id is set
  // explicitly from elsewhere.
  void SetAppId(std::optional<webapps::AppId> app_id);

  // Called by `WebAppBrowserController` and `WebKioskBrowserControllerBase`'s
  // `OnTabInserted` and `OnTabRemoved` methods to indicate if this web contents
  // is currently being displayed inside an app window. `window_app_id` is the
  // id of the app.
  void SetIsInAppWindow(std::optional<webapps::AppId> window_app_id);

  void SetCallbackToRunOnTabChanges(base::OnceClosure callback);

  // Used to listen to the tab entering the background via the `TabInterface`.
  void OnTabBackgrounded(tabs::TabInterface* tab_interface);

  // Used to listen to the tab being detached from the tab strip via the
  // `TabInterface`. The tab will either be destroyed, or is in the middle of
  // being put in a different window.
  void OnTabDetached(tabs::TabInterface* tab_interface,
                     tabs::TabInterface::DetachReason detach_reason);

  const base::UnguessableToken& GetAudioFocusGroupIdForTesting() const;

  // Returns the installed web app that 'controls' the last committed url of
  // this tab. This is populated for this tab no matter where it is, whether in
  // a browser window, or in a standalone app window.
  // - 'controls' means it's the web app who's scope contains the last committed
  //    url. If there are multiple web apps that satisfy this constraint, then
  //    it chooses the one with the longest (aka most specific) scope prefix.
  // - 'installed' means the web app is
  //   InstallState::INSTALLED_WITH_OS_INTEGRATION or
  //   InstallState::INSTALLED_WITHOUT_OS_INTEGRATION (which is usually only
  //   preinstalled apps). And thus this excludes the
  //   InstallState::SUGGESTED_FROM_ANOTHER_DEVICE state.
  //
  // Note: This is populated on construction from the current tab's
  // `GetLastCommittedURL()`, and afterwards only after navigation is committed.
  //
  // Note: If we are in an app window, this is not guaranteed to match
  // `window_app_id()` - for example, if the web contents of an app navigates
  // out of scope of the app, this will be std::nullopt.
  const std::optional<webapps::AppId>& app_id() const { return app_id_; }

  // Returns the installed web app window that contains this tab, or
  // std::nullopt if this tab is in a normal browser window. This is not
  // guaranteed to match `app_id()`, because app windows can display content
  // that is out of scope of the app (and even in scope of another app).
  const std::optional<webapps::AppId>& window_app_id() const {
    return window_app_id_;
  }

  // True when this web contents is currently being displayed inside an app
  // window instead of in a browser tab.
  bool is_in_app_window() const { return window_app_id_.has_value(); }

  bool is_pinned_home_tab() const { return is_pinned_home_tab_; }
  void set_is_pinned_home_tab(bool is_pinned_home_tab) {
    is_pinned_home_tab_ = is_pinned_home_tab;
  }

  webapps::LaunchQueue& EnsureLaunchQueue();

  // content::WebContentsObserver:
  void ReadyToCommitNavigation(
      content::NavigationHandle* navigation_handle) override;
  void PrimaryPageChanged(content::Page& page) override;
  void DidFinishLoad(content::RenderFrameHost* render_frame_host,
                     const GURL& validated_url) override;

  // Because the launch queue is communicated via a dedicated mojo pipe,
  // ordering can be tricky in tests. This method allows tests to call
  // `FlushForTesting()` on the launch queue mojo connection to ensure that all
  // launch queue messages have been sent to the renderer.
  void FlushLaunchQueueForTesting() const;

  // Returns if the current web contents can be used for the 'focus-existing'
  // behavior of navigation capturing, where the tab is focused and a
  // 'LaunchParams' is given to a javascript 'launch consumer' on the page. This
  // returns if the current page can feasibly run javascript to actually set
  // this launch consumer, as without that, any captured links would simply do
  // nothing.
  // Specifically, this turns `true` if the current page's mime-type is html or
  // xhtml.
  bool CanBeUsedForFocusExisting() const;

 private:
  friend class WebAppAudioFocusBrowserTest;
  friend class content::WebContentsUserData<WebAppTabHelper>;

  // WebAppInstallManagerObserver:
  void OnWebAppInstalled(const webapps::AppId& installed_app_id) override;
  void OnWebAppWillBeUninstalled(
      const webapps::AppId& uninstalled_app_id) override;
  void OnWebAppInstallManagerDestroyed() override;

  void ResetTabSubscriptions(tabs::TabInterface* tab);

  // Sets the state of this tab helper. This will call
  // `WebAppUiManager::OnAssociatedAppChanged` if the id has changed, and
  // `UpdateAudioFocusGroupId()` if either has changed.
  void SetState(std::optional<webapps::AppId> app_id,
                std::optional<webapps::AppId> window_app_id);

  // Runs any logic when the associated app is added, changed or removed.
  void OnAssociatedAppChanged(
      const std::optional<webapps::AppId>& previous_app_id,
      const std::optional<webapps::AppId>& new_app_id);

  // Updates the audio focus group id based on the current web app.
  void UpdateAudioFocusGroupId();

  // Triggers a reinstall of a placeholder app for |url|.
  void ReinstallPlaceholderAppIfNecessary(const GURL& url);

  // When a `TabInterface` is updated on being detached and attached to a new
  // window, update the subscriptions as needed.
  void SubscribeToTabState(tabs::TabInterface* tab_interface);

  // Asynchronously run `on_tab_details_changed_callback_` after tab states have
  // changed.
  void MaybeNotifyTabChanged();

  // Cache the information that an app launch has happened and a WebFeature use
  // counter needs to be measured. Trigger measurement which may or may not
  // happen depending on whether page load has finished.
  void ScheduleManifestAppliedUseCounter();

  // Record the `UseCounter` for an app launch after page loading has
  // completed. Resets all flags post `UseCounter` measurement so that this
  // happens only once.
  void MaybeRecordManifestAppliedUseCounter();

  std::optional<webapps::AppId> app_id_;
  std::optional<webapps::AppId> window_app_id_;

  // True when this tab is the pinned home tab of a tabbed web app.
  bool is_pinned_home_tab_ = false;

  // The audio focus group id is used to group media sessions together for apps.
  // We store the applied group id locally on the helper for testing.
  base::UnguessableToken audio_focus_group_id_ = base::UnguessableToken::Null();

  // Use unique_ptr for lazy instantiation as most browser tabs have no need to
  // incur this memory overhead.
  std::unique_ptr<webapps::LaunchQueue> launch_queue_;

  // A callback that runs whenever the `tab` is destroyed, navigates or goes to
  // the background.
  base::OnceClosure on_tab_details_changed_callback_;

  // Used to subscribe to various changes happening in the current tab from the
  // `TabInterface`.
  std::vector<base::CallbackListSubscription> tab_subscriptions_;

  // Listen to whether page load has completed in the web contents to measure
  // the `UseCounter` of launching a web app.
  bool can_record_manifest_applied_ = false;

  // Cache the information that an app launch `UseCounter` needs to be measured.
  bool meaure_manifest_applied_use_counter_ = false;

  base::ScopedObservation<WebAppInstallManager, WebAppInstallManagerObserver>
      observation_{this};
  raw_ptr<WebAppProvider> provider_ = nullptr;

  base::WeakPtrFactory<WebAppTabHelper> weak_factory_{this};

  WEB_CONTENTS_USER_DATA_KEY_DECL();
};

}  // namespace web_app

#endif  // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_TAB_HELPER_H_