OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |