Loading core/java/android/view/View.java +56 −77 Original line number Diff line number Diff line Loading @@ -3373,9 +3373,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * |-------|-------|-------|-------| * 1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_ON_LAYOUT * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_ADDED * 1 PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED * |-------|-------|-------|-------| */ Loading @@ -3396,28 +3395,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Variables used to control when the IntelligenceManager.notifyNodeAdded()/removed() methods * should be called. * * The idea is to call notifyNodeAdded() after the view is layout and visible, then call * notifyNodeRemoved() when it's gone (without known when it was removed from the parent). * * TODO(b/111276913): the current algortighm could probably be optimized and some of them * removed * The idea is to call notifyAppeared() after the view is layout and visible, then call * notifyDisappeared() when it's gone (without known when it was removed from the parent). */ private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_ON_LAYOUT = 0x10; private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_ADDED = 0x20; private static final int PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE = 0x40; private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10; private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20; /* End of masks for mPrivateFlags4 */ private static final int CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED = 1; private static final int CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED = 0; @IntDef(flag = true, prefix = { "CONTENT_CAPTURE_NOTIFICATION_TYPE_" }, value = { CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED, CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED }) @Retention(RetentionPolicy.SOURCE) private @interface ContentCaptureNotificationType {} /** @hide */ protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0; /** @hide */ Loading Loading @@ -8933,63 +8918,61 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Helper used to notify the {@link IntelligenceManager} when the view is removed or * added, based on whether it's laid out and visible, and without knowing if the parent removed * it from the view hierarchy. * * <p>This method is called from many places (visibility changed, view laid out, view attached * or detached to/from window, etc...) and hence must contain the logic to call the manager, as * described below: * * <ol> * <li>It should only be called when content capture is enabled for the view. * <li>It must call viewAppeared() before viewDisappeared() * <li>viewAppearead() can only be called when the view is visible and laidout * <li>It should not call the same event twice. * </ol> */ // TODO(b/111276913): make sure the current algorithm covers all cases. For example, it should // probably be called every time notifyEnterOrExitForAutoFillIfNeeded() is called as well. private void notifyNodeAddedOrRemovedForContentCaptureIfNeeded( @ContentCaptureNotificationType int type) { if (type != CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED && type != CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED) { // Sanity check so it does not screw up the flags Log.wtf(CONTENT_CAPTURE_LOG_TAG, "notifyNodeAddedOrRemovedForContentCaptureIfNeeded(): " + "invalid type " + type + " for " + this); return; } if (!isImportantForContentCapture()) return; private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) { final IntelligenceManager im = mContext.getSystemService(IntelligenceManager.class); if (im == null || !im.isContentCaptureEnabled()) return; // Make sure event is notified just once, and reset the // PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE flag boolean ignoreNotification = false; if (type == CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED) { if ((mPrivateFlags4 & PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE) == CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED) { ignoreNotification = true; } else { mPrivateFlags4 |= PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE; } } else { if ((mPrivateFlags4 & PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE) == CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED) { ignoreNotification = true; } else { mPrivateFlags4 &= ~PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE; } } if (ignoreNotification) { // NOTE: isImportantForContentCapture() is more expensive than im.isContentCaptureEnabled() if (!isImportantForContentCapture()) return; if (appeared) { if (!isLaidOut() || !isVisibleToUser() || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) { if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { // TODO(b/111276913): remove this log statement if the algorithm is not improved // (right now it's called too many times when the activity is stopped and/or views // disappear Log.v(CONTENT_CAPTURE_LOG_TAG, "notifyNodeAddedOrRemovedForContentCaptureIfNeeded(" + type + "): ignoring repeated notification on " + this); Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid=" + isLaidOut() + ", visible=" + isVisibleToUser() + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0)); } return; } if (type == CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED) { // All good: notify the manager... final ViewStructure structure = im.newViewStructure(this); onProvideContentCaptureStructure(structure, /* flags= */ 0); im.notifyViewAppeared(structure); mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_ADDED; // ...and set the flags mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; } else { if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_ADDED) == 0) { return; // skip initial notification if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) == 0 || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0) { if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": notifiedAppeared=" + ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0)); } return; } // All good: notify the manager... im.notifyViewDisappeared(getAutofillId()); // ...and set the flags mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; } } Loading Loading @@ -12896,6 +12879,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public void dispatchStartTemporaryDetach() { mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; notifyEnterOrExitForAutoFillIfNeeded(false); notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); onStartTemporaryDetach(); } Loading @@ -12922,6 +12906,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, notifyFocusChangeToInputMethodManager(true /* hasFocus */); } notifyEnterOrExitForAutoFillIfNeeded(true); notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } /** Loading Loading @@ -13503,9 +13488,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); } } notifyNodeAddedOrRemovedForContentCaptureIfNeeded(isVisible ? CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED : CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED); notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); } /** Loading Loading @@ -19076,6 +19060,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, needGlobalAttributesUpdate(false); notifyEnterOrExitForAutoFillIfNeeded(true); notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } @UnsupportedAppUsage Loading Loading @@ -19125,8 +19110,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } notifyEnterOrExitForAutoFillIfNeeded(false); notifyNodeAddedOrRemovedForContentCaptureIfNeeded( CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED); notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); } /** Loading Loading @@ -21432,12 +21416,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, notifyEnterOrExitForAutoFillIfNeeded(true); } if ((mViewFlags & VISIBILITY_MASK) == VISIBLE && (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_ON_LAYOUT) == 0) { notifyNodeAddedOrRemovedForContentCaptureIfNeeded( CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED); mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_ON_LAYOUT; } notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } private boolean hasParentWantsFocus() { core/java/android/widget/TextView.java +3 −0 Original line number Diff line number Diff line Loading @@ -10942,6 +10942,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (!isPassword || viewFor == VIEW_STRUCTURE_FOR_AUTOFILL || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { if (mLayout == null) { if (viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { Log.w(LOG_TAG, "onProvideContentCaptureStructure(): calling assumeLayout()"); } assumeLayout(); } Layout layout = mLayout; Loading Loading
core/java/android/view/View.java +56 −77 Original line number Diff line number Diff line Loading @@ -3373,9 +3373,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * |-------|-------|-------|-------| * 1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_ON_LAYOUT * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_ADDED * 1 PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED * |-------|-------|-------|-------| */ Loading @@ -3396,28 +3395,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Variables used to control when the IntelligenceManager.notifyNodeAdded()/removed() methods * should be called. * * The idea is to call notifyNodeAdded() after the view is layout and visible, then call * notifyNodeRemoved() when it's gone (without known when it was removed from the parent). * * TODO(b/111276913): the current algortighm could probably be optimized and some of them * removed * The idea is to call notifyAppeared() after the view is layout and visible, then call * notifyDisappeared() when it's gone (without known when it was removed from the parent). */ private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_ON_LAYOUT = 0x10; private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_ADDED = 0x20; private static final int PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE = 0x40; private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10; private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20; /* End of masks for mPrivateFlags4 */ private static final int CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED = 1; private static final int CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED = 0; @IntDef(flag = true, prefix = { "CONTENT_CAPTURE_NOTIFICATION_TYPE_" }, value = { CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED, CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED }) @Retention(RetentionPolicy.SOURCE) private @interface ContentCaptureNotificationType {} /** @hide */ protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0; /** @hide */ Loading Loading @@ -8933,63 +8918,61 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Helper used to notify the {@link IntelligenceManager} when the view is removed or * added, based on whether it's laid out and visible, and without knowing if the parent removed * it from the view hierarchy. * * <p>This method is called from many places (visibility changed, view laid out, view attached * or detached to/from window, etc...) and hence must contain the logic to call the manager, as * described below: * * <ol> * <li>It should only be called when content capture is enabled for the view. * <li>It must call viewAppeared() before viewDisappeared() * <li>viewAppearead() can only be called when the view is visible and laidout * <li>It should not call the same event twice. * </ol> */ // TODO(b/111276913): make sure the current algorithm covers all cases. For example, it should // probably be called every time notifyEnterOrExitForAutoFillIfNeeded() is called as well. private void notifyNodeAddedOrRemovedForContentCaptureIfNeeded( @ContentCaptureNotificationType int type) { if (type != CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED && type != CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED) { // Sanity check so it does not screw up the flags Log.wtf(CONTENT_CAPTURE_LOG_TAG, "notifyNodeAddedOrRemovedForContentCaptureIfNeeded(): " + "invalid type " + type + " for " + this); return; } if (!isImportantForContentCapture()) return; private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) { final IntelligenceManager im = mContext.getSystemService(IntelligenceManager.class); if (im == null || !im.isContentCaptureEnabled()) return; // Make sure event is notified just once, and reset the // PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE flag boolean ignoreNotification = false; if (type == CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED) { if ((mPrivateFlags4 & PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE) == CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED) { ignoreNotification = true; } else { mPrivateFlags4 |= PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE; } } else { if ((mPrivateFlags4 & PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE) == CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED) { ignoreNotification = true; } else { mPrivateFlags4 &= ~PFLAG4_LAST_CONTENT_CAPTURE_NOTIFICATION_TYPE; } } if (ignoreNotification) { // NOTE: isImportantForContentCapture() is more expensive than im.isContentCaptureEnabled() if (!isImportantForContentCapture()) return; if (appeared) { if (!isLaidOut() || !isVisibleToUser() || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) { if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { // TODO(b/111276913): remove this log statement if the algorithm is not improved // (right now it's called too many times when the activity is stopped and/or views // disappear Log.v(CONTENT_CAPTURE_LOG_TAG, "notifyNodeAddedOrRemovedForContentCaptureIfNeeded(" + type + "): ignoring repeated notification on " + this); Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid=" + isLaidOut() + ", visible=" + isVisibleToUser() + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0)); } return; } if (type == CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED) { // All good: notify the manager... final ViewStructure structure = im.newViewStructure(this); onProvideContentCaptureStructure(structure, /* flags= */ 0); im.notifyViewAppeared(structure); mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_ADDED; // ...and set the flags mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; } else { if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_ADDED) == 0) { return; // skip initial notification if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) == 0 || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0) { if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": notifiedAppeared=" + ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0)); } return; } // All good: notify the manager... im.notifyViewDisappeared(getAutofillId()); // ...and set the flags mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; } } Loading Loading @@ -12896,6 +12879,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public void dispatchStartTemporaryDetach() { mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; notifyEnterOrExitForAutoFillIfNeeded(false); notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); onStartTemporaryDetach(); } Loading @@ -12922,6 +12906,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, notifyFocusChangeToInputMethodManager(true /* hasFocus */); } notifyEnterOrExitForAutoFillIfNeeded(true); notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } /** Loading Loading @@ -13503,9 +13488,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); } } notifyNodeAddedOrRemovedForContentCaptureIfNeeded(isVisible ? CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED : CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED); notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); } /** Loading Loading @@ -19076,6 +19060,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, needGlobalAttributesUpdate(false); notifyEnterOrExitForAutoFillIfNeeded(true); notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } @UnsupportedAppUsage Loading Loading @@ -19125,8 +19110,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } notifyEnterOrExitForAutoFillIfNeeded(false); notifyNodeAddedOrRemovedForContentCaptureIfNeeded( CONTENT_CAPTURE_NOTIFICATION_TYPE_DISAPPEARED); notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); } /** Loading Loading @@ -21432,12 +21416,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, notifyEnterOrExitForAutoFillIfNeeded(true); } if ((mViewFlags & VISIBILITY_MASK) == VISIBLE && (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_ON_LAYOUT) == 0) { notifyNodeAddedOrRemovedForContentCaptureIfNeeded( CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED); mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_ON_LAYOUT; } notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } private boolean hasParentWantsFocus() {
core/java/android/widget/TextView.java +3 −0 Original line number Diff line number Diff line Loading @@ -10942,6 +10942,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (!isPassword || viewFor == VIEW_STRUCTURE_FOR_AUTOFILL || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { if (mLayout == null) { if (viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { Log.w(LOG_TAG, "onProvideContentCaptureStructure(): calling assumeLayout()"); } assumeLayout(); } Layout layout = mLayout; Loading