Loading core/java/android/view/View.java +25 −3 Original line number Original line Diff line number Diff line Loading @@ -858,6 +858,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ */ static boolean sHasFocusableExcludeAutoFocusable; static boolean sHasFocusableExcludeAutoFocusable; /** * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly * made focusable by default. As a result, apps could (incorrectly) change the clickable * setting of views off the UI thread. Now that clickable can effect the focusable state, * changing the clickable attribute off the UI thread will cause an exception (since changing * the focusable state checks). In order to prevent apps from crashing, we will handle this * specific case and just not notify parents on new focusables resulting from marking views * clickable from outside the UI thread. */ private static boolean sAutoFocusableOffUIThreadWontNotifyParents; /** @hide */ /** @hide */ @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) @Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE) Loading Loading @@ -4182,6 +4193,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; sCompatibilityDone = true; sCompatibilityDone = true; } } } } Loading Loading @@ -12135,6 +12148,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, int privateFlags = mPrivateFlags; int privateFlags = mPrivateFlags; // If focusable is auto, update the FOCUSABLE bit. // If focusable is auto, update the FOCUSABLE bit. int focusableChangedByAuto = 0; if (((mViewFlags & FOCUSABLE_AUTO) != 0) if (((mViewFlags & FOCUSABLE_AUTO) != 0) && (changed & (FOCUSABLE_MASK | CLICKABLE | FOCUSABLE_IN_TOUCH_MODE)) != 0) { && (changed & (FOCUSABLE_MASK | CLICKABLE | FOCUSABLE_IN_TOUCH_MODE)) != 0) { int newFocus = NOT_FOCUSABLE; int newFocus = NOT_FOCUSABLE; Loading @@ -12144,8 +12158,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mViewFlags = (mViewFlags & ~FOCUSABLE_IN_TOUCH_MODE); mViewFlags = (mViewFlags & ~FOCUSABLE_IN_TOUCH_MODE); } } mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; int focusChanged = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); changed = (changed & ~FOCUSABLE) | focusChanged; changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; } } /* Check if the FOCUSABLE bit has changed */ /* Check if the FOCUSABLE bit has changed */ Loading @@ -12160,7 +12174,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Tell the view system that we are now available to take focus * Tell the view system that we are now available to take focus * if no one else already has it. * if no one else already has it. */ */ if (mParent != null) mParent.focusableViewAvailable(this); if (mParent != null) { ViewRootImpl viewRootImpl = getViewRootImpl(); if (!sAutoFocusableOffUIThreadWontNotifyParents || focusableChangedByAuto == 0 || viewRootImpl == null || viewRootImpl.mThread == Thread.currentThread()) { mParent.focusableViewAvailable(this); } } } } } } Loading Loading
core/java/android/view/View.java +25 −3 Original line number Original line Diff line number Diff line Loading @@ -858,6 +858,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ */ static boolean sHasFocusableExcludeAutoFocusable; static boolean sHasFocusableExcludeAutoFocusable; /** * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly * made focusable by default. As a result, apps could (incorrectly) change the clickable * setting of views off the UI thread. Now that clickable can effect the focusable state, * changing the clickable attribute off the UI thread will cause an exception (since changing * the focusable state checks). In order to prevent apps from crashing, we will handle this * specific case and just not notify parents on new focusables resulting from marking views * clickable from outside the UI thread. */ private static boolean sAutoFocusableOffUIThreadWontNotifyParents; /** @hide */ /** @hide */ @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) @Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE) Loading Loading @@ -4182,6 +4193,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; sCompatibilityDone = true; sCompatibilityDone = true; } } } } Loading Loading @@ -12135,6 +12148,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, int privateFlags = mPrivateFlags; int privateFlags = mPrivateFlags; // If focusable is auto, update the FOCUSABLE bit. // If focusable is auto, update the FOCUSABLE bit. int focusableChangedByAuto = 0; if (((mViewFlags & FOCUSABLE_AUTO) != 0) if (((mViewFlags & FOCUSABLE_AUTO) != 0) && (changed & (FOCUSABLE_MASK | CLICKABLE | FOCUSABLE_IN_TOUCH_MODE)) != 0) { && (changed & (FOCUSABLE_MASK | CLICKABLE | FOCUSABLE_IN_TOUCH_MODE)) != 0) { int newFocus = NOT_FOCUSABLE; int newFocus = NOT_FOCUSABLE; Loading @@ -12144,8 +12158,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mViewFlags = (mViewFlags & ~FOCUSABLE_IN_TOUCH_MODE); mViewFlags = (mViewFlags & ~FOCUSABLE_IN_TOUCH_MODE); } } mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; int focusChanged = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); changed = (changed & ~FOCUSABLE) | focusChanged; changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; } } /* Check if the FOCUSABLE bit has changed */ /* Check if the FOCUSABLE bit has changed */ Loading @@ -12160,7 +12174,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Tell the view system that we are now available to take focus * Tell the view system that we are now available to take focus * if no one else already has it. * if no one else already has it. */ */ if (mParent != null) mParent.focusableViewAvailable(this); if (mParent != null) { ViewRootImpl viewRootImpl = getViewRootImpl(); if (!sAutoFocusableOffUIThreadWontNotifyParents || focusableChangedByAuto == 0 || viewRootImpl == null || viewRootImpl.mThread == Thread.currentThread()) { mParent.focusableViewAvailable(this); } } } } } } Loading