Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(98)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/tab/TabChromeWebContentsDelegateAndroid.java

Issue 1358923002: Extract TabChromeWebContentsDelegateAndroid into a separate class. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@chrometab10
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.tab;
6
7 import android.annotation.TargetApi;
8 import android.app.ActivityManager;
9 import android.content.Context;
10 import android.content.Intent;
11 import android.graphics.Rect;
12 import android.media.AudioManager;
13 import android.os.Build;
14 import android.util.Log;
15 import android.util.Pair;
16 import android.view.KeyEvent;
17 import android.view.View;
18
19 import org.chromium.base.ObserverList.RewindableIterator;
20 import org.chromium.chrome.R;
21 import org.chromium.chrome.browser.ChromeActivity;
22 import org.chromium.chrome.browser.ChromeApplication;
23 import org.chromium.chrome.browser.ChromeWebContentsDelegateAndroid;
24 import org.chromium.chrome.browser.RepostFormWarningDialog;
25 import org.chromium.chrome.browser.document.DocumentUtils;
26 import org.chromium.chrome.browser.document.DocumentWebContentsDelegate;
27 import org.chromium.chrome.browser.media.MediaCaptureNotificationService;
28 import org.chromium.chrome.browser.policy.PolicyAuditor;
29 import org.chromium.chrome.browser.policy.PolicyAuditor.AuditEvent;
30 import org.chromium.chrome.browser.tabmodel.TabCreatorManager.TabCreator;
31 import org.chromium.chrome.browser.tabmodel.TabModel;
32 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
33 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
34 import org.chromium.chrome.browser.util.FeatureUtilities;
35 import org.chromium.content_public.browser.InvalidateTypes;
36 import org.chromium.content_public.browser.WebContents;
37 import org.chromium.ui.WindowOpenDisposition;
38
39 /**
40 * A basic {@link ChromeWebContentsDelegateAndroid} that forwards some calls to the registered
41 * {@link TabObserver}s.
42 */
43 public class TabChromeWebContentsDelegateAndroid
44 extends ChromeWebContentsDelegateAndroid {
Maria 2015/09/22 21:01:50 What do you think about merging this class with Ch
45 /** Used for logging. */
46 private static final String TAG = "TabChromeWebContentsDelegateAndroid";
Maria 2015/09/22 21:01:50 I think the presubmit will make you switch to usin
aurimas (slooooooooow) 2015/09/22 22:44:46 Done
47
48 private final Tab mTab;
49 private final ChromeActivity mActivity;
50
51
Maria 2015/09/22 21:01:50 remove one newline
aurimas (slooooooooow) 2015/09/22 22:44:46 Done
52 private final Runnable mCloseContentsRunnable = new Runnable() {
53 @Override
54 public void run() {
55 boolean isSelected = mActivity.getTabModelSelector().getCurrentTab() == mTab;
56 mActivity.getTabModelSelector().closeTab(mTab);
57
58 // If the parent Tab belongs to another Activity, fire the Intent to bring it back.
59 if (isSelected && mTab.getParentIntent() != null
60 && mActivity.getIntent() != mTab.getParentIntent()) {
61 boolean mayLaunch = FeatureUtilities.isDocumentMode(mActivity)
62 ? isParentInAndroidOverview() : true;
63 if (mayLaunch) mActivity.startActivity(mTab.getParentIntent());
64 }
65 }
66
67 /** If the API allows it, returns whether a Task still exists for the pa rent Activity. */
68 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
69 private boolean isParentInAndroidOverview() {
70 ActivityManager activityManager =
71 (ActivityManager) mActivity.getSystemService(Context.ACTIVIT Y_SERVICE);
72 for (ActivityManager.AppTask task : activityManager.getAppTasks()) {
73 Intent taskIntent = DocumentUtils.getBaseIntentFromTask(task);
74 if (taskIntent != null && taskIntent.filterEquals(mTab.getParent Intent())) {
75 return true;
76 }
77 }
78 return false;
79 }
80 };
81
82 public TabChromeWebContentsDelegateAndroid(Tab tab, ChromeActivity activity) {
83 mTab = tab;
84 mActivity = activity;
85 }
86
87 @Override
88 public void onLoadProgressChanged(int progress) {
89 if (!mTab.isLoading()) return;
90 mTab.notifyLoadProgress(mTab.getProgress());
91 }
92
93 @Override
94 public void onLoadStarted() {
95 RewindableIterator<TabObserver> observers = mTab.getTabObservers();
96 while (observers.hasNext()) {
97 observers.next().onLoadStarted(mTab);
98 }
99 }
100
101 @Override
102 public void onLoadStopped() {
103 RewindableIterator<TabObserver> observers = mTab.getTabObservers();
104 while (observers.hasNext()) {
105 observers.next().onLoadStopped(mTab);
106 }
107 }
108
109 @Override
110 public void onUpdateUrl(String url) {
111 RewindableIterator<TabObserver> observers = mTab.getTabObservers();
112 while (observers.hasNext()) {
113 observers.next().onUpdateUrl(mTab, url);
114 }
115 }
116
117 @Override
118 public void showRepostFormWarningDialog() {
119 mTab.resetSwipeRefreshHandler();
120 RepostFormWarningDialog warningDialog = new RepostFormWarningDialog(
121 new Runnable() {
122 @Override
123 public void run() {
124 mTab.getWebContents().getNavigationController().cancelPe ndingReload();
125 }
126 }, new Runnable() {
127 @Override
128 public void run() {
129 mTab.getWebContents().getNavigationController().continue PendingReload();
130 }
131 });
132 warningDialog.show(mActivity.getFragmentManager(), null);
133 }
134
135 @Override
136 public void toggleFullscreenModeForTab(boolean enableFullscreen) {
137 if (mTab.getFullscreenManager() != null) {
138 mTab.getFullscreenManager().setPersistentFullscreenMode(enableFullsc reen);
139 }
140
141 RewindableIterator<TabObserver> observers = mTab.getTabObservers();
142 while (observers.hasNext()) {
143 observers.next().onToggleFullscreenMode(mTab, enableFullscreen);
144 }
145 }
146
147 @Override
148 public void navigationStateChanged(int flags) {
149 if ((flags & InvalidateTypes.TAB) != 0) {
150 MediaCaptureNotificationService.updateMediaNotificationForTab(
151 mTab.getApplicationContext(), mTab.getId(), isCapturingAudio (),
152 isCapturingVideo(), mTab.getUrl());
153 }
154 if ((flags & InvalidateTypes.TITLE) != 0) {
155 // Update cached title then notify observers.
156 mTab.updateTitle();
157 }
158 if ((flags & InvalidateTypes.URL) != 0) {
159 RewindableIterator<TabObserver> observers = mTab.getTabObservers();
160 while (observers.hasNext()) {
161 observers.next().onUrlUpdated(mTab);
162 }
163 }
164 }
165
166 @Override
167 public void visibleSSLStateChanged() {
168 RewindableIterator<TabObserver> observers = mTab.getTabObservers();
169 while (observers.hasNext()) {
170 observers.next().onSSLStateUpdated(mTab);
171 }
172 }
173
174 @Override
175 public void webContentsCreated(WebContents sourceWebContents, long openerRen derFrameId,
176 String frameName, String targetUrl, WebContents newWebContents) {
177 RewindableIterator<TabObserver> observers = mTab.getTabObservers();
178 while (observers.hasNext()) {
179 observers.next().webContentsCreated(mTab, sourceWebContents, openerR enderFrameId,
180 frameName, targetUrl, newWebContents);
181 }
182 // The URL can't be taken from the WebContents if it's paused. Save it for later.
183 assert mWebContentsUrlMapping == null;
184 mWebContentsUrlMapping = Pair.create(newWebContents, targetUrl);
185
186 // TODO(dfalcantara): Re-remove this once crbug.com/508366 is fixed.
187 TabCreator tabCreator = mActivity.getTabCreator(mTab.isIncognito());
188
189 if (tabCreator != null && tabCreator.createsTabsAsynchronously()) {
190 DocumentWebContentsDelegate.getInstance().attachDelegate(newWebConte nts);
191 }
192 }
193
194 @Override
195 public void rendererUnresponsive() {
196 super.rendererUnresponsive();
197 mTab.handleRendererUnresponsive();
198 }
199
200 @Override
201 public void rendererResponsive() {
202 super.rendererResponsive();
203 mTab.handleRendererResponsive();
204 }
205
206 @Override
207 public boolean isFullscreenForTabOrPending() {
208 return mTab.getFullscreenManager() == null
209 ? false : mTab.getFullscreenManager().getPersistentFullscreenMod e();
210 }
211
212 @Override
213 public void openNewTab(String url, String extraHeaders, byte[] postData, int disposition,
214 boolean isRendererInitiated) {
215 mTab.openNewTab(url, extraHeaders, postData, disposition, true, isRender erInitiated);
216 }
217
218 private Pair<WebContents, String> mWebContentsUrlMapping;
219
220 protected TabModel getTabModel() {
221 // TODO(dfalcantara): Remove this when DocumentActivity.getTabModelSelec tor()
222 // can return a TabModelSelector that activateContent s() can use.
223 return mActivity.getTabModelSelector().getModel(mTab.isIncognito());
224 }
225
226 @Override
227 public boolean shouldResumeRequestsForCreatedWindow() {
228 // Pause the WebContents if an Activity has to be created for it first.
229 TabCreator tabCreator = mActivity.getTabCreator(mTab.isIncognito());
230 assert tabCreator != null;
231 return !tabCreator.createsTabsAsynchronously();
232 }
233
234 @Override
235 public boolean addNewContents(WebContents sourceWebContents, WebContents web Contents,
236 int disposition, Rect initialPosition, boolean userGesture) {
237 assert mWebContentsUrlMapping.first == webContents;
238
239 TabCreator tabCreator = mActivity.getTabCreator(mTab.isIncognito());
240 assert tabCreator != null;
241
242 // Grab the URL, which might not be available via the Tab.
243 String url = mWebContentsUrlMapping.second;
244 mWebContentsUrlMapping = null;
245
246 // Skip opening a new Tab if it doesn't make sense.
247 if (mTab.isClosing()) return false;
248
249 // Creating new Tabs asynchronously requires starting a new Activity to create the Tab,
250 // so the Tab returned will always be null. There's no way to know sync hronously
251 // whether the Tab is created, so assume it's always successful.
252 boolean createdSuccessfully = tabCreator.createTabWithWebContents(
253 webContents, mTab.getId(), TabLaunchType.FROM_LONGPRESS_FOREGROU ND, url);
254 boolean success = tabCreator.createsTabsAsynchronously() || createdSucce ssfully;
255 if (success && disposition == WindowOpenDisposition.NEW_POPUP) {
256 PolicyAuditor auditor =
257 ((ChromeApplication) mTab.getApplicationContext()).getPolicy Auditor();
258 auditor.notifyAuditEvent(mTab.getApplicationContext(),
259 AuditEvent.OPEN_POPUP_URL_SUCCESS, url, "");
260 }
261
262 return success;
263 }
264
265 @Override
266 public void activateContents() {
267 boolean activityIsDestroyed = false;
268 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
269 activityIsDestroyed = mActivity.isDestroyed();
270 }
271 if (activityIsDestroyed || !mTab.isInitialized()) {
272 Log.e(TAG, "Activity destroyed before calling activateContents(). B ailing out.");
273 return;
274 }
275
276 TabModel model = getTabModel();
277 int index = model.indexOf(mTab);
278 if (index == TabModel.INVALID_TAB_INDEX) return;
279 TabModelUtils.setIndex(model, index);
280 bringActivityToForeground();
281 }
282
283 /**
284 * Brings chrome's Activity to foreground, if it is not so.
285 */
286 protected void bringActivityToForeground() {
287 // This intent is sent in order to get the activity back to the foregrou nd if it was
288 // not already. The previous call will activate the right tab in the con text of the
289 // TabModel but will only show the tab to the user if Chrome was already in the
290 // foreground.
291 // The intent is getting the tabId mostly because it does not cost much to do so.
292 // When receiving the intent, the tab associated with the tabId should a lready be
293 // active.
294 // Note that calling only the intent in order to activate the tab is sli ghtly slower
295 // because it will change the tab when the intent is handled, which happ ens after
296 // Chrome gets back to the foreground.
297 Intent newIntent = Tab.createBringTabToFrontIntent(mTab.getId());
298 newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
299
300 mTab.getApplicationContext().startActivity(newIntent);
301 }
302
303 @Override
304 public void closeContents() {
305 // Execute outside of callback, otherwise we end up deleting the native
306 // objects in the middle of executing methods on them.
307 mTab.getHandler().removeCallbacks(mCloseContentsRunnable);
308 mTab.getHandler().post(mCloseContentsRunnable);
Maria 2015/09/22 21:01:50 I think instead of exposing tab's handler for this
aurimas (slooooooooow) 2015/09/22 22:44:46 Done
309 }
310
311 @Override
312 public boolean takeFocus(boolean reverse) {
313 if (reverse) {
314 View menuButton = mActivity.findViewById(R.id.menu_button);
315 if (menuButton == null || !menuButton.isShown()) {
316 menuButton = mActivity.findViewById(R.id.document_menu_button);
317 }
318 if (menuButton != null && menuButton.isShown()) {
319 return menuButton.requestFocus();
320 }
321
322 View tabSwitcherButton = mActivity.findViewById(R.id.tab_switcher_bu tton);
323 if (tabSwitcherButton != null && tabSwitcherButton.isShown()) {
324 return tabSwitcherButton.requestFocus();
325 }
326 } else {
327 View urlBar = mActivity.findViewById(R.id.url_bar);
328 if (urlBar != null) return urlBar.requestFocus();
329 }
330 return false;
331 }
332
333 @Override
334 public void handleKeyboardEvent(KeyEvent event) {
335 if (event.getAction() == KeyEvent.ACTION_DOWN) {
336 if (mActivity.onKeyDown(event.getKeyCode(), event)) return;
337
338 // Handle the Escape key here (instead of in KeyboardShortcuts.java) , so it doesn't
339 // interfere with other parts of the activity (e.g. the URL bar).
340 if (event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE && event.hasNoModi fiers()) {
341 WebContents wc = mTab.getWebContents();
342 if (wc != null) wc.stop();
343 return;
344 }
345 }
346 handleMediaKey(event);
347 }
348
349 /**
350 * Redispatches unhandled media keys. This allows bluetooth headphones with play/pause or
351 * other buttons to function correctly.
352 */
353 @TargetApi(19)
354 private void handleMediaKey(KeyEvent e) {
355 if (Build.VERSION.SDK_INT < 19) return;
356 switch (e.getKeyCode()) {
357 case KeyEvent.KEYCODE_MUTE:
358 case KeyEvent.KEYCODE_HEADSETHOOK:
359 case KeyEvent.KEYCODE_MEDIA_PLAY:
360 case KeyEvent.KEYCODE_MEDIA_PAUSE:
361 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
362 case KeyEvent.KEYCODE_MEDIA_STOP:
363 case KeyEvent.KEYCODE_MEDIA_NEXT:
364 case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
365 case KeyEvent.KEYCODE_MEDIA_REWIND:
366 case KeyEvent.KEYCODE_MEDIA_RECORD:
367 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
368 case KeyEvent.KEYCODE_MEDIA_CLOSE:
369 case KeyEvent.KEYCODE_MEDIA_EJECT:
370 case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
371 AudioManager am = (AudioManager) mActivity.getSystemService(
372 Context.AUDIO_SERVICE);
373 am.dispatchMediaKeyEvent(e);
374 break;
375 default:
376 break;
377 }
378 }
379
380 /**
381 * @return Whether audio is being captured.
382 */
383 private boolean isCapturingAudio() {
384 return !mTab.isClosing()
385 && ChromeWebContentsDelegateAndroid.nativeIsCapturingAudio(mTab. getWebContents());
386 }
387
388 /**
389 * @return Whether video is being captured.
390 */
391 private boolean isCapturingVideo() {
392 return !mTab.isClosing()
393 && ChromeWebContentsDelegateAndroid.nativeIsCapturingVideo(mTab. getWebContents());
394 }
395 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698