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

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java

Issue 2779033004: [Android] Focus/Blur contents when window focus changes (Closed)
Patch Set: Address comments Created 3 years, 8 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
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.content.browser; 5 package org.chromium.content.browser;
6 6
7 import android.annotation.SuppressLint; 7 import android.annotation.SuppressLint;
8 import android.annotation.TargetApi; 8 import android.annotation.TargetApi;
9 import android.app.assist.AssistStructure.ViewNode; 9 import android.app.assist.AssistStructure.ViewNode;
10 import android.content.ClipData; 10 import android.content.ClipData;
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 // side would prevent garbage collection of the ContentViewCore (as that str ong ref would 105 // side would prevent garbage collection of the ContentViewCore (as that str ong ref would
106 // create a new GC root). 106 // create a new GC root).
107 // For that reason, we store only a weak reference to the interface object o n the 107 // For that reason, we store only a weak reference to the interface object o n the
108 // native side. However we still need a strong reference on the Java side to 108 // native side. However we still need a strong reference on the Java side to
109 // prevent garbage collection if the embedder doesn't maintain their own ref to the 109 // prevent garbage collection if the embedder doesn't maintain their own ref to the
110 // interface object - the Java side ref won't create a new GC root. 110 // interface object - the Java side ref won't create a new GC root.
111 // This map stores those references. We put into the map on addJavaScriptInt erface() 111 // This map stores those references. We put into the map on addJavaScriptInt erface()
112 // and remove from it in removeJavaScriptInterface(). The annotation class i s stored for 112 // and remove from it in removeJavaScriptInterface(). The annotation class i s stored for
113 // the purpose of migrating injected objects from one instance of CVC to ano ther, which 113 // the purpose of migrating injected objects from one instance of CVC to ano ther, which
114 // is used by Android WebView to support WebChromeClient.onCreateWindow scen ario. 114 // is used by Android WebView to support WebChromeClient.onCreateWindow scen ario.
115 private final Map<String, Pair<Object, Class>> mJavaScriptInterfaces = 115 private final Map<String, Pair<Object, Class>> mJavaScriptInterfaces = new H ashMap<>();
aelias_OOO_until_Jul13 2017/03/30 02:06:55 I assume you made these changes because of a presu
mthiesse 2017/03/30 14:51:51 My editor automatically makes these changes, and I
116 new HashMap<String, Pair<Object, Class>>();
117 116
118 // Additionally, we keep track of all Java bound JS objects that are in use on the 117 // Additionally, we keep track of all Java bound JS objects that are in use on the
119 // current page to ensure that they are not garbage collected until the page is 118 // current page to ensure that they are not garbage collected until the page is
120 // navigated. This includes interface objects that have been removed 119 // navigated. This includes interface objects that have been removed
121 // via the removeJavaScriptInterface API and transient objects returned from methods 120 // via the removeJavaScriptInterface API and transient objects returned from methods
122 // on the interface object. Note we use HashSet rather than Set as the nativ e side 121 // on the interface object. Note we use HashSet rather than Set as the nativ e side
123 // expects HashSet (no bindings for interfaces). 122 // expects HashSet (no bindings for interfaces).
124 private final HashSet<Object> mRetainedJavaScriptObjects = new HashSet<Objec t>(); 123 private final HashSet<Object> mRetainedJavaScriptObjects = new HashSet<>();
125 124
126 /** 125 /**
127 * A {@link WebContentsObserver} that listens to frame navigation events. 126 * A {@link WebContentsObserver} that listens to frame navigation events.
128 */ 127 */
129 private static class ContentViewWebContentsObserver extends WebContentsObser ver { 128 private static class ContentViewWebContentsObserver extends WebContentsObser ver {
130 // Using a weak reference avoids cycles that might prevent GC of WebView 's WebContents. 129 // Using a weak reference avoids cycles that might prevent GC of WebView 's WebContents.
131 private final WeakReference<ContentViewCore> mWeakContentViewCore; 130 private final WeakReference<ContentViewCore> mWeakContentViewCore;
132 131
133 ContentViewWebContentsObserver(ContentViewCore contentViewCore) { 132 ContentViewWebContentsObserver(ContentViewCore contentViewCore) {
134 super(contentViewCore.getWebContents()); 133 super(contentViewCore.getWebContents());
135 mWeakContentViewCore = new WeakReference<ContentViewCore>(contentVie wCore); 134 mWeakContentViewCore = new WeakReference<>(contentViewCore);
136 } 135 }
137 136
138 @Override 137 @Override
139 public void didFinishNavigation(String url, boolean isInMainFrame, boole an isErrorPage, 138 public void didFinishNavigation(String url, boolean isInMainFrame, boole an isErrorPage,
140 boolean hasCommitted, boolean isSameDocument, boolean isFragment Navigation, 139 boolean hasCommitted, boolean isSameDocument, boolean isFragment Navigation,
141 Integer pageTransition, int errorCode, String errorDescription, 140 Integer pageTransition, int errorCode, String errorDescription,
142 int httpStatusCode) { 141 int httpStatusCode) {
143 determinedProcessVisibility(); 142 determinedProcessVisibility();
144 143
145 if (hasCommitted && isInMainFrame && !isSameDocument) { 144 if (hasCommitted && isInMainFrame && !isSameDocument) {
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 // screen orientation. 363 // screen orientation.
365 private boolean mFullscreenRequiredForOrientationLock = true; 364 private boolean mFullscreenRequiredForOrientationLock = true;
366 365
367 // A ViewAndroidDelegate that delegates to the current container view. 366 // A ViewAndroidDelegate that delegates to the current container view.
368 private ViewAndroidDelegate mViewAndroidDelegate; 367 private ViewAndroidDelegate mViewAndroidDelegate;
369 368
370 // NOTE: This object will not be released by Android framework until the mat ching 369 // NOTE: This object will not be released by Android framework until the mat ching
371 // ResultReceiver in the InputMethodService (IME app) gets gc'ed. 370 // ResultReceiver in the InputMethodService (IME app) gets gc'ed.
372 private ShowKeyboardResultReceiver mShowKeyboardResultReceiver; 371 private ShowKeyboardResultReceiver mShowKeyboardResultReceiver;
373 372
373 // Whether this ContentViewCore has view focus.
374 private boolean mHasViewFocus;
375 // Whether this ContentViewCore has window focus.
376 private boolean mHasWindowFocus;
377
374 // The list of observers that are notified when ContentViewCore changes its WindowAndroid. 378 // The list of observers that are notified when ContentViewCore changes its WindowAndroid.
375 private final ObserverList<WindowAndroidChangedObserver> mWindowAndroidChang edObservers; 379 private final ObserverList<WindowAndroidChangedObserver> mWindowAndroidChang edObservers;
376 380
377 /** 381 /**
378 * @param webContents The {@link WebContents} to find a {@link ContentViewCo re} of. 382 * @param webContents The {@link WebContents} to find a {@link ContentViewCo re} of.
379 * @return A {@link ContentViewCore} that is connected to {@code webContents} or 383 * @return A {@link ContentViewCore} that is connected to {@code webContents} or
380 * {@code null} if none exists. 384 * {@code null} if none exists.
381 */ 385 */
382 public static ContentViewCore fromWebContents(WebContents webContents) { 386 public static ContentViewCore fromWebContents(WebContents webContents) {
383 return nativeFromWebContentsAndroid(webContents); 387 return nativeFromWebContentsAndroid(webContents);
384 } 388 }
385 389
386 /** 390 /**
387 * Constructs a new ContentViewCore. Embedders must call initialize() after constructing 391 * Constructs a new ContentViewCore. Embedders must call initialize() after constructing
388 * a ContentViewCore and before using it. 392 * a ContentViewCore and before using it.
389 * 393 *
390 * @param context The context used to create this. 394 * @param context The context used to create this.
391 */ 395 */
392 public ContentViewCore(Context context, String productVersion) { 396 public ContentViewCore(Context context, String productVersion) {
393 mContext = context; 397 mContext = context;
394 mProductVersion = productVersion; 398 mProductVersion = productVersion;
395 mRenderCoordinates = new RenderCoordinates(); 399 mRenderCoordinates = new RenderCoordinates();
396 mAccessibilityManager = (AccessibilityManager) 400 mAccessibilityManager = (AccessibilityManager)
397 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); 401 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
398 mSystemCaptioningBridge = CaptioningBridgeFactory.getSystemCaptioningBri dge(mContext); 402 mSystemCaptioningBridge = CaptioningBridgeFactory.getSystemCaptioningBri dge(mContext);
399 mGestureStateListeners = new ObserverList<GestureStateListener>(); 403 mGestureStateListeners = new ObserverList<>();
400 mGestureStateListenersIterator = mGestureStateListeners.rewindableIterat or(); 404 mGestureStateListenersIterator = mGestureStateListeners.rewindableIterat or();
401 405
402 mWindowAndroidChangedObservers = new ObserverList<WindowAndroidChangedOb server>(); 406 mWindowAndroidChangedObservers = new ObserverList<>();
403 } 407 }
404 408
405 /** 409 /**
406 * @return The context used for creating this ContentViewCore. 410 * @return The context used for creating this ContentViewCore.
407 */ 411 */
408 @CalledByNative 412 @CalledByNative
409 public Context getContext() { 413 public Context getContext() {
410 return mContext; 414 return mContext;
411 } 415 }
412 416
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
669 */ 673 */
670 public void setContainerView(ViewGroup containerView) { 674 public void setContainerView(ViewGroup containerView) {
671 try { 675 try {
672 TraceEvent.begin("ContentViewCore.setContainerView"); 676 TraceEvent.begin("ContentViewCore.setContainerView");
673 if (mContainerView != null) { 677 if (mContainerView != null) {
674 hideSelectPopupWithCancelMessage(); 678 hideSelectPopupWithCancelMessage();
675 mPopupZoomer.hide(false); 679 mPopupZoomer.hide(false);
676 } 680 }
677 681
678 mContainerView = containerView; 682 mContainerView = containerView;
683 onFocusChangedInternal(getRealWindowFocusedState(), containerView.ha sFocus(),
684 false /* hideKeyboardOnBlur */);
679 mContainerView.setClickable(true); 685 mContainerView.setClickable(true);
680 if (mSelectionPopupController != null) { 686 if (mSelectionPopupController != null) {
681 mSelectionPopupController.setContainerView(containerView); 687 mSelectionPopupController.setContainerView(containerView);
682 } 688 }
683 } finally { 689 } finally {
684 TraceEvent.end("ContentViewCore.setContainerView"); 690 TraceEvent.end("ContentViewCore.setContainerView");
685 } 691 }
686 } 692 }
687 693
694 /**
695 * Note: We don't use View#hasWindowFocus() because it returns incorrect val ues when the View
696 * doesn't have View focus.
697 * @return Whether the containerView actually has Window focus.
698 */
699 private boolean getRealWindowFocusedState() {
700 boolean hasWindowFocus = false;
701 int[] states = mContainerView.getDrawableState();
702 for (int state : states) {
703 if ((state & android.R.attr.state_window_focused) != 0) hasWindowFoc us = true;
704 }
705 return hasWindowFocus;
706 }
707
688 @CalledByNative 708 @CalledByNative
689 private void onNativeContentViewCoreDestroyed(long nativeContentViewCore) { 709 private void onNativeContentViewCoreDestroyed(long nativeContentViewCore) {
690 assert nativeContentViewCore == mNativeContentViewCore; 710 assert nativeContentViewCore == mNativeContentViewCore;
691 mNativeContentViewCore = 0; 711 mNativeContentViewCore = 0;
692 } 712 }
693 713
694 /** 714 /**
695 * Set the Container view Internals. 715 * Set the Container view Internals.
696 * @param internalDispatcher Handles dispatching all hidden or super methods to the 716 * @param internalDispatcher Handles dispatching all hidden or super methods to the
697 * containerView. 717 * containerView.
(...skipping 629 matching lines...) Expand 10 before | Expand all | Expand 10 after
1327 private void cancelRequestToScrollFocusedEditableNodeIntoView() { 1347 private void cancelRequestToScrollFocusedEditableNodeIntoView() {
1328 // Zero-ing the rect will prevent |updateAfterSizeChanged()| from 1348 // Zero-ing the rect will prevent |updateAfterSizeChanged()| from
1329 // issuing the delayed form focus event. 1349 // issuing the delayed form focus event.
1330 mFocusPreOSKViewportRect.setEmpty(); 1350 mFocusPreOSKViewportRect.setEmpty();
1331 } 1351 }
1332 1352
1333 /** 1353 /**
1334 * @see View#onWindowFocusChanged(boolean) 1354 * @see View#onWindowFocusChanged(boolean)
1335 */ 1355 */
1336 public void onWindowFocusChanged(boolean hasWindowFocus) { 1356 public void onWindowFocusChanged(boolean hasWindowFocus) {
1357 if (mHasWindowFocus == hasWindowFocus) return;
1337 mImeAdapter.onWindowFocusChanged(hasWindowFocus); 1358 mImeAdapter.onWindowFocusChanged(hasWindowFocus);
1338 if (!hasWindowFocus) resetGestureDetection(); 1359 if (!hasWindowFocus) resetGestureDetection();
1339 mSelectionPopupController.onWindowFocusChanged(hasWindowFocus); 1360 mSelectionPopupController.onWindowFocusChanged(hasWindowFocus);
1340 for (mGestureStateListenersIterator.rewind(); mGestureStateListenersIter ator.hasNext();) { 1361 for (mGestureStateListenersIterator.rewind(); mGestureStateListenersIter ator.hasNext();) {
1341 mGestureStateListenersIterator.next().onWindowFocusChanged(hasWindow Focus); 1362 mGestureStateListenersIterator.next().onWindowFocusChanged(hasWindow Focus);
1342 } 1363 }
1364 onFocusChangedInternal(hasWindowFocus, mHasViewFocus, true /* hideKeyboa rdOnBlur */);
1343 } 1365 }
1344 1366
1345 public void onFocusChanged(boolean gainFocus, boolean hideKeyboardOnBlur) { 1367 public void onFocusChanged(boolean gainFocus, boolean hideKeyboardOnBlur) {
aelias_OOO_until_Jul13 2017/03/30 02:06:55 Please rename "gainFocus" to "hasViewFocus"
mthiesse 2017/03/30 14:51:51 Done.
1346 mImeAdapter.onViewFocusChanged(gainFocus, hideKeyboardOnBlur); 1368 if (mHasViewFocus == gainFocus) return;
1369 onFocusChangedInternal(mHasWindowFocus, gainFocus, hideKeyboardOnBlur);
1370 }
1371
1372 @VisibleForTesting
1373 public void onFocusChangedInternal(
1374 boolean hasWindowFocus, boolean hasViewFocus, boolean hideKeyboardOn Blur) {
1375 boolean hadInputFocus = mHasWindowFocus && mHasViewFocus;
1376 boolean hasInputFocus = hasWindowFocus && hasViewFocus;
1377 mHasWindowFocus = hasWindowFocus;
1378 mHasViewFocus = hasViewFocus;
1379 if (hasInputFocus == hadInputFocus) return;
aelias_OOO_until_Jul13 2017/03/30 02:06:55 This early-return seems to do nothing given the ot
mthiesse 2017/03/30 14:51:51 It doesn't do nothing - it stops us from doing wor
1380 mImeAdapter.onViewFocusChanged(hasInputFocus, hideKeyboardOnBlur);
1347 1381
1348 // Used in test that bypasses initialize(). 1382 // Used in test that bypasses initialize().
1349 if (mJoystickScrollProvider != null) { 1383 if (mJoystickScrollProvider != null) {
1350 mJoystickScrollProvider.setEnabled(gainFocus && !isFocusedNodeEditab le()); 1384 mJoystickScrollProvider.setEnabled(hasInputFocus && !isFocusedNodeEd itable());
1351 } 1385 }
1352 1386
1353 if (gainFocus) { 1387 if (hasInputFocus) {
1354 restoreSelectionPopupsIfNecessary(); 1388 restoreSelectionPopupsIfNecessary();
1355 } else { 1389 } else {
1356 cancelRequestToScrollFocusedEditableNodeIntoView(); 1390 cancelRequestToScrollFocusedEditableNodeIntoView();
1357 if (mPreserveSelectionOnNextLossOfFocus) { 1391 if (mPreserveSelectionOnNextLossOfFocus) {
1358 mPreserveSelectionOnNextLossOfFocus = false; 1392 mPreserveSelectionOnNextLossOfFocus = false;
1359 hidePopupsAndPreserveSelection(); 1393 hidePopupsAndPreserveSelection();
1360 } else { 1394 } else {
1361 hidePopupsAndClearSelection(); 1395 hidePopupsAndClearSelection();
1362 // Clear the selection. The selection is cleared on destroying I ME 1396 // Clear the selection. The selection is cleared on destroying I ME
1363 // and also here since we may receive destroy first, for example 1397 // and also here since we may receive destroy first, for example
1364 // when focus is lost in webview. 1398 // when focus is lost in webview.
1365 clearSelection(); 1399 clearSelection();
1366 } 1400 }
1367 } 1401 }
1368 if (mNativeContentViewCore != 0) nativeSetFocus(mNativeContentViewCore, gainFocus); 1402 if (mNativeContentViewCore != 0) nativeSetFocus(mNativeContentViewCore, hasInputFocus);
1369 } 1403 }
1370 1404
1371 /** 1405 /**
1372 * @see View#onKeyUp(int, KeyEvent) 1406 * @see View#onKeyUp(int, KeyEvent)
1373 */ 1407 */
1374 public boolean onKeyUp(int keyCode, KeyEvent event) { 1408 public boolean onKeyUp(int keyCode, KeyEvent event) {
1375 if (mPopupZoomer.isShowing() && keyCode == KeyEvent.KEYCODE_BACK) { 1409 if (mPopupZoomer.isShowing() && keyCode == KeyEvent.KEYCODE_BACK) {
1376 mPopupZoomer.backButtonPressed(); 1410 mPopupZoomer.backButtonPressed();
1377 return true; 1411 return true;
1378 } 1412 }
(...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after
1815 if (mContainerView.getParent() == null || mContainerView.getVisibility() != View.VISIBLE) { 1849 if (mContainerView.getParent() == null || mContainerView.getVisibility() != View.VISIBLE) {
1816 mNativeSelectPopupSourceFrame = nativeSelectPopupSourceFrame; 1850 mNativeSelectPopupSourceFrame = nativeSelectPopupSourceFrame;
1817 selectPopupMenuItems(null); 1851 selectPopupMenuItems(null);
1818 return; 1852 return;
1819 } 1853 }
1820 1854
1821 hidePopupsAndClearSelection(); 1855 hidePopupsAndClearSelection();
1822 assert mNativeSelectPopupSourceFrame == 0 : "Zombie popup did not clear the frame source"; 1856 assert mNativeSelectPopupSourceFrame == 0 : "Zombie popup did not clear the frame source";
1823 1857
1824 assert items.length == enabled.length; 1858 assert items.length == enabled.length;
1825 List<SelectPopupItem> popupItems = new ArrayList<SelectPopupItem>(); 1859 List<SelectPopupItem> popupItems = new ArrayList<>();
1826 for (int i = 0; i < items.length; i++) { 1860 for (int i = 0; i < items.length; i++) {
1827 popupItems.add(new SelectPopupItem(items[i], enabled[i])); 1861 popupItems.add(new SelectPopupItem(items[i], enabled[i]));
1828 } 1862 }
1829 if (DeviceFormFactor.isTablet(mContext) && !multiple && !isTouchExplorat ionEnabled()) { 1863 if (DeviceFormFactor.isTablet(mContext) && !multiple && !isTouchExplorat ionEnabled()) {
1830 mSelectPopup = new SelectPopupDropdown( 1864 mSelectPopup = new SelectPopupDropdown(
1831 this, anchorView, popupItems, selectedIndices, rightAligned) ; 1865 this, anchorView, popupItems, selectedIndices, rightAligned) ;
1832 } else { 1866 } else {
1833 if (getWindowAndroid() == null) return; 1867 if (getWindowAndroid() == null) return;
1834 Context windowContext = getWindowAndroid().getContext().get(); 1868 Context windowContext = getWindowAndroid().getContext().get();
1835 if (windowContext == null) return; 1869 if (windowContext == null) return;
(...skipping 840 matching lines...) Expand 10 before | Expand all | Expand 10 after
2676 private native void nativeSetTextTrackSettings(long nativeContentViewCoreImp l, 2710 private native void nativeSetTextTrackSettings(long nativeContentViewCoreImp l,
2677 boolean textTracksEnabled, String textTrackBackgroundColor, String t extTrackFontFamily, 2711 boolean textTracksEnabled, String textTrackBackgroundColor, String t extTrackFontFamily,
2678 String textTrackFontStyle, String textTrackFontVariant, String textT rackTextColor, 2712 String textTrackFontStyle, String textTrackFontVariant, String textT rackTextColor,
2679 String textTrackTextShadow, String textTrackTextSize); 2713 String textTrackTextShadow, String textTrackTextSize);
2680 2714
2681 private native void nativeSetBackgroundOpaque(long nativeContentViewCoreImpl , boolean opaque); 2715 private native void nativeSetBackgroundOpaque(long nativeContentViewCoreImpl , boolean opaque);
2682 private native boolean nativeIsTouchDragDropEnabled(long nativeContentViewCo reImpl); 2716 private native boolean nativeIsTouchDragDropEnabled(long nativeContentViewCo reImpl);
2683 private native void nativeOnDragEvent(long nativeContentViewCoreImpl, int ac tion, int x, int y, 2717 private native void nativeOnDragEvent(long nativeContentViewCoreImpl, int ac tion, int x, int y,
2684 int screenX, int screenY, String[] mimeTypes, String content); 2718 int screenX, int screenY, String[] mimeTypes, String content);
2685 } 2719 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698