Loading core/java/android/view/AccessibilityInteractionController.java +22 −14 Original line number Diff line number Diff line Loading @@ -491,20 +491,28 @@ final class AccessibilityInteractionController { if ((direction & View.FOCUS_ACCESSIBILITY) == View.FOCUS_ACCESSIBILITY) { AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider(); if (provider != null) { next = provider.accessibilityFocusSearch(direction, virtualDescendantId); } else if (virtualDescendantId == View.NO_ID) { next = provider.accessibilityFocusSearch(direction, virtualDescendantId); if (next != null) { return; } } View nextView = root.focusSearch(direction); if (nextView != null) { while (nextView != null) { // If the focus search reached a node with a provider // we delegate to the provider to find the next one. // If the provider does not return a virtual view to // take accessibility focus we try the next view found // by the focus search algorithm. provider = nextView.getAccessibilityNodeProvider(); if (provider != null) { next = provider.accessibilityFocusSearch(direction, virtualDescendantId); next = provider.accessibilityFocusSearch(direction, View.NO_ID); if (next != null) { break; } nextView = nextView.focusSearch(direction); } else { next = nextView.createAccessibilityNodeInfo(); } break; } } } else { Loading core/java/android/view/View.java +8 −5 Original line number Diff line number Diff line Loading @@ -6027,7 +6027,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal return; } if ((focusableMode & FOCUSABLES_ACCESSIBILITY) == FOCUSABLES_ACCESSIBILITY) { if (canTakeAccessibilityFocusFromHover()) { if (canTakeAccessibilityFocusFromHover() || getAccessibilityNodeProvider() != null) { views.add(this); return; } Loading Loading @@ -6156,12 +6156,15 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * @hide */ public void clearAccessibilityFocus() { if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) { mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED; ViewRootImpl viewRootImpl = getViewRootImpl(); if (viewRootImpl != null) { View focusHost = viewRootImpl.getAccessibilityFocusedHost(); if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { viewRootImpl.setAccessibilityFocusedHost(null); } } if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) { mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED; invalidate(); sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); notifyAccessibilityStateChanged(); Loading core/java/android/view/ViewRootImpl.java +74 −5 Original line number Diff line number Diff line Loading @@ -489,6 +489,8 @@ public final class ViewRootImpl implements ViewParent, mWindowAttributes.copyFrom(attrs); attrs = mWindowAttributes; setAccessibilityFocusedHost(null); if (view instanceof RootViewSurfaceTaker) { mSurfaceHolderCallback = ((RootViewSurfaceTaker)view).willYouTakeTheSurface(); Loading Loading @@ -556,6 +558,7 @@ public final class ViewRootImpl implements ViewParent, mInputChannel = null; mFallbackEventHandler.setView(null); unscheduleTraversals(); setAccessibilityFocusedHost(null); throw new RuntimeException("Adding window failed", e); } finally { if (restore) { Loading @@ -575,6 +578,7 @@ public final class ViewRootImpl implements ViewParent, mAdded = false; mFallbackEventHandler.setView(null); unscheduleTraversals(); setAccessibilityFocusedHost(null); switch (res) { case WindowManagerImpl.ADD_BAD_APP_TOKEN: case WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN: Loading Loading @@ -635,8 +639,6 @@ public final class ViewRootImpl implements ViewParent, if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); } setAccessibilityFocusedHost(null); } } } Loading Loading @@ -2543,11 +2545,51 @@ public final class ViewRootImpl implements ViewParent, } void setAccessibilityFocusedHost(View host) { if (mAccessibilityFocusedHost != null && mAccessibilityFocusedVirtualView == null) { // If we have a virtual view with accessibility focus we need // to clear the focus and invalidate the virtual view bounds. if (mAccessibilityFocusedVirtualView != null) { AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView; View focusHost = mAccessibilityFocusedHost; focusHost.clearAccessibilityFocusNoCallbacks(); // Wipe the state of the current accessibility focus since // the call into the provider to clear accessibility focus // will fire an accessibility event which will end up calling // this method and we want to have clean state when this // invocation happens. mAccessibilityFocusedHost = null; mAccessibilityFocusedVirtualView = null; AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider(); if (provider != null) { // Invalidate the area of the cleared accessibility focus. focusNode.getBoundsInParent(mTempRect); focusHost.invalidate(mTempRect); // Clear accessibility focus in the virtual node. final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId( focusNode.getSourceNodeId()); provider.performAction(virtualNodeId, AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); } } if (mAccessibilityFocusedHost != null) { // Clear accessibility focus in the view. mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(); } // Set the new focus host. mAccessibilityFocusedHost = host; mAccessibilityFocusedVirtualView = null; // If the host has a provide find the virtual descendant that has focus. if (mAccessibilityFocusedHost != null) { AccessibilityNodeProvider provider = mAccessibilityFocusedHost.getAccessibilityNodeProvider(); if (provider != null) { mAccessibilityFocusedVirtualView = provider.findAccessibilityFocus(View.NO_ID); return; } } } public void requestChildFocus(View child, View focused) { Loading Loading @@ -2633,6 +2675,8 @@ public final class ViewRootImpl implements ViewParent, destroyHardwareRenderer(); setAccessibilityFocusedHost(null); mView = null; mAttachInfo.mRootView = null; mAttachInfo.mSurface = null; Loading Loading @@ -4608,6 +4652,31 @@ public final class ViewRootImpl implements ViewParent, if (mView == null) { return false; } // Watch for accessibility focus change events from virtual nodes // to keep track of accessibility focus being on a virtual node. final int eventType = event.getEventType(); switch (eventType) { case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: { final long sourceId = event.getSourceNodeId(); // If the event is not from a virtual node we are not interested. final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(sourceId); if (virtualViewId == AccessibilityNodeInfo.UNDEFINED) { break; } final int realViewId = AccessibilityNodeInfo.getAccessibilityViewId(sourceId); View focusHost = mView.findViewByAccessibilityId(realViewId); setAccessibilityFocusedHost(focusHost); } break; case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: { final long sourceId = event.getSourceNodeId(); // If the event is not from a virtual node we are not interested. final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(sourceId); if (virtualViewId == AccessibilityNodeInfo.UNDEFINED) { break; } setAccessibilityFocusedHost(null); } break; } mAccessibilityManager.sendAccessibilityEvent(event); return true; } Loading core/java/android/widget/NumberPicker.java +242 −12 Original line number Diff line number Diff line Loading @@ -950,6 +950,8 @@ public class NumberPicker extends LinearLayout { provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); mLastHoveredChildVirtualViewId = hoveredVirtualViewId; provider.performAction(hoveredVirtualViewId, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); } break; case MotionEvent.ACTION_HOVER_MOVE: { if (mLastHoveredChildVirtualViewId != hoveredVirtualViewId Loading @@ -960,6 +962,8 @@ public class NumberPicker extends LinearLayout { provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); mLastHoveredChildVirtualViewId = hoveredVirtualViewId; provider.performAction(hoveredVirtualViewId, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); } } break; case MotionEvent.ACTION_HOVER_EXIT: { Loading Loading @@ -1413,9 +1417,16 @@ public class NumberPicker extends LinearLayout { } @Override public void sendAccessibilityEvent(int eventType) { // Do not send accessibility events - we want the user to // perceive this widget as several controls rather as a whole. public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { // We do not want the real descendant to be considered focus search // since it is managed by the accessibility node provider. if ((focusableMode & FOCUSABLES_ACCESSIBILITY) == FOCUSABLES_ACCESSIBILITY) { if (canTakeAccessibilityFocusFromHover() || getAccessibilityNodeProvider() != null) { views.add(this); return; } } super.addFocusables(views, direction, focusableMode); } @Override Loading Loading @@ -2072,7 +2083,12 @@ public class NumberPicker extends LinearLayout { } } /** * Class for managing virtual view tree rooted at this picker. */ class AccessibilityNodeProviderImpl extends AccessibilityNodeProvider { private static final int UNDEFINED = Integer.MIN_VALUE; private static final int VIRTUAL_VIEW_ID_INCREMENT = 1; private static final int VIRTUAL_VIEW_ID_INPUT = 2; Loading @@ -2083,6 +2099,8 @@ public class NumberPicker extends LinearLayout { private final int[] mTempArray = new int[2]; private int mAccessibilityFocusedView = UNDEFINED; @Override public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { switch (virtualViewId) { Loading Loading @@ -2137,6 +2155,25 @@ public class NumberPicker extends LinearLayout { @Override public boolean performAction(int virtualViewId, int action, Bundle arguments) { switch (virtualViewId) { case View.NO_ID: { switch (action) { case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView != virtualViewId) { mAccessibilityFocusedView = virtualViewId; requestAccessibilityFocus(); return true; } } return false; case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView == virtualViewId) { mAccessibilityFocusedView = UNDEFINED; clearAccessibilityFocus(); return true; } return false; } } } break; case VIRTUAL_VIEW_ID_INPUT: { switch (action) { case AccessibilityNodeInfo.ACTION_FOCUS: { Loading @@ -2149,25 +2186,182 @@ public class NumberPicker extends LinearLayout { mInputText.clearFocus(); return true; } return false; } case AccessibilityNodeInfo.ACTION_CLICK: { showSoftInput(); return true; } case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView != virtualViewId) { mAccessibilityFocusedView = virtualViewId; sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); mInputText.invalidate(); return true; } } return false; case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView == virtualViewId) { mAccessibilityFocusedView = UNDEFINED; sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); mInputText.invalidate(); return true; } } return false; default: { return mInputText.performAccessibilityAction(action, arguments); } } } return false; case VIRTUAL_VIEW_ID_INCREMENT: { switch (action) { case AccessibilityNodeInfo.ACTION_CLICK: { NumberPicker.this.changeValueByOne(true); sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_CLICKED); } return true; case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView != virtualViewId) { mAccessibilityFocusedView = virtualViewId; sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); return true; } } return false; case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView == virtualViewId) { mAccessibilityFocusedView = UNDEFINED; sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); return true; } } return false; } } return false; case VIRTUAL_VIEW_ID_DECREMENT: { switch (action) { case AccessibilityNodeInfo.ACTION_CLICK: { final boolean increment = (virtualViewId == VIRTUAL_VIEW_ID_INCREMENT); NumberPicker.this.changeValueByOne(increment); sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_CLICKED); } return true; case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView != virtualViewId) { mAccessibilityFocusedView = virtualViewId; sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); invalidate(0, 0, mRight, mTopSelectionDividerTop); return true; } } return false; case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView == virtualViewId) { mAccessibilityFocusedView = UNDEFINED; sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); invalidate(0, 0, mRight, mTopSelectionDividerTop); return true; } } return false; } } return false; } return super.performAction(virtualViewId, action, arguments); } @Override public AccessibilityNodeInfo findAccessibilityFocus(int virtualViewId) { return createAccessibilityNodeInfo(mAccessibilityFocusedView); } @Override public AccessibilityNodeInfo accessibilityFocusSearch(int direction, int virtualViewId) { switch (direction) { case View.ACCESSIBILITY_FOCUS_DOWN: case View.ACCESSIBILITY_FOCUS_FORWARD: { switch (mAccessibilityFocusedView) { case UNDEFINED: { return createAccessibilityNodeInfo(View.NO_ID); } case View.NO_ID: { if (hasVirtualDecrementButton()) { return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT); } } //$FALL-THROUGH$ case VIRTUAL_VIEW_ID_DECREMENT: { return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT); } case VIRTUAL_VIEW_ID_INPUT: { if (hasVirtualIncrementButton()) { return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT); } } //$FALL-THROUGH$ case VIRTUAL_VIEW_ID_INCREMENT: { View nextFocus = NumberPicker.this.focusSearch(direction); if (nextFocus != null) { return nextFocus.createAccessibilityNodeInfo(); } return null; } } } break; case View.ACCESSIBILITY_FOCUS_UP: case View.ACCESSIBILITY_FOCUS_BACKWARD: { switch (mAccessibilityFocusedView) { case UNDEFINED: { return createAccessibilityNodeInfo(View.NO_ID); } case View.NO_ID: { if (hasVirtualIncrementButton()) { return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT); } } //$FALL-THROUGH$ case VIRTUAL_VIEW_ID_INCREMENT: { return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT); } case VIRTUAL_VIEW_ID_INPUT: { if (hasVirtualDecrementButton()) { return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT); } } //$FALL-THROUGH$ case VIRTUAL_VIEW_ID_DECREMENT: { View nextFocus = NumberPicker.this.focusSearch(direction); if (nextFocus != null) { return nextFocus.createAccessibilityNodeInfo(); } return null; } } } break; } return super.performAction(virtualViewId, action, arguments); return null; } public void sendAccessibilityEventForVirtualView(int virtualViewId, int eventType) { switch (virtualViewId) { case VIRTUAL_VIEW_ID_DECREMENT: { if (hasVirtualDecrementButton()) { sendAccessibilityEventForVirtualButton(virtualViewId, eventType, getVirtualDecrementButtonText()); } } break; case VIRTUAL_VIEW_ID_INPUT: { sendAccessibilityEventForVirtualText(eventType); } break; case VIRTUAL_VIEW_ID_INCREMENT: { if (hasVirtualIncrementButton()) { sendAccessibilityEventForVirtualButton(virtualViewId, eventType, getVirtualIncrementButtonText()); } } break; } } Loading Loading @@ -2227,8 +2421,13 @@ public class NumberPicker extends LinearLayout { private AccessibilityNodeInfo createAccessibiltyNodeInfoForInputText() { AccessibilityNodeInfo info = mInputText.createAccessibilityNodeInfo(); info.setLongClickable(true); info.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); if (mAccessibilityFocusedView != VIRTUAL_VIEW_ID_INPUT) { info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); } if (mAccessibilityFocusedView == VIRTUAL_VIEW_ID_INPUT) { info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); } return info; } Loading @@ -2252,6 +2451,15 @@ public class NumberPicker extends LinearLayout { getLocationOnScreen(locationOnScreen); boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]); info.setBoundsInScreen(boundsInScreen); if (mAccessibilityFocusedView != virtualViewId) { info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); } if (mAccessibilityFocusedView == virtualViewId) { info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); } info.addAction(AccessibilityNodeInfo.ACTION_CLICK); return info; } Loading @@ -2261,9 +2469,15 @@ public class NumberPicker extends LinearLayout { info.setClassName(NumberPicker.class.getName()); info.setPackageName(mContext.getPackageName()); info.setSource(NumberPicker.this); if (hasVirtualDecrementButton()) { info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_DECREMENT); } info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); if (hasVirtualIncrementButton()) { info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INCREMENT); } info.setParent((View) getParent()); info.setEnabled(NumberPicker.this.isEnabled()); info.setScrollable(true); Loading @@ -2276,9 +2490,25 @@ public class NumberPicker extends LinearLayout { getLocationOnScreen(locationOnScreen); boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]); info.setBoundsInScreen(boundsInScreen); if (mAccessibilityFocusedView != View.NO_ID) { info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); } if (mAccessibilityFocusedView == View.NO_ID) { info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); } return info; } private boolean hasVirtualDecrementButton() { return getWrapSelectorWheel() || getValue() > getMinValue(); } private boolean hasVirtualIncrementButton() { return getWrapSelectorWheel() || getValue() < getMaxValue(); } private String getVirtualDecrementButtonText() { int value = mValue - 1; if (mWrapSelectorWheel) { Loading core/res/res/layout/time_picker_holo.xml +1 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/view/AccessibilityInteractionController.java +22 −14 Original line number Diff line number Diff line Loading @@ -491,20 +491,28 @@ final class AccessibilityInteractionController { if ((direction & View.FOCUS_ACCESSIBILITY) == View.FOCUS_ACCESSIBILITY) { AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider(); if (provider != null) { next = provider.accessibilityFocusSearch(direction, virtualDescendantId); } else if (virtualDescendantId == View.NO_ID) { next = provider.accessibilityFocusSearch(direction, virtualDescendantId); if (next != null) { return; } } View nextView = root.focusSearch(direction); if (nextView != null) { while (nextView != null) { // If the focus search reached a node with a provider // we delegate to the provider to find the next one. // If the provider does not return a virtual view to // take accessibility focus we try the next view found // by the focus search algorithm. provider = nextView.getAccessibilityNodeProvider(); if (provider != null) { next = provider.accessibilityFocusSearch(direction, virtualDescendantId); next = provider.accessibilityFocusSearch(direction, View.NO_ID); if (next != null) { break; } nextView = nextView.focusSearch(direction); } else { next = nextView.createAccessibilityNodeInfo(); } break; } } } else { Loading
core/java/android/view/View.java +8 −5 Original line number Diff line number Diff line Loading @@ -6027,7 +6027,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal return; } if ((focusableMode & FOCUSABLES_ACCESSIBILITY) == FOCUSABLES_ACCESSIBILITY) { if (canTakeAccessibilityFocusFromHover()) { if (canTakeAccessibilityFocusFromHover() || getAccessibilityNodeProvider() != null) { views.add(this); return; } Loading Loading @@ -6156,12 +6156,15 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * @hide */ public void clearAccessibilityFocus() { if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) { mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED; ViewRootImpl viewRootImpl = getViewRootImpl(); if (viewRootImpl != null) { View focusHost = viewRootImpl.getAccessibilityFocusedHost(); if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { viewRootImpl.setAccessibilityFocusedHost(null); } } if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) { mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED; invalidate(); sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); notifyAccessibilityStateChanged(); Loading
core/java/android/view/ViewRootImpl.java +74 −5 Original line number Diff line number Diff line Loading @@ -489,6 +489,8 @@ public final class ViewRootImpl implements ViewParent, mWindowAttributes.copyFrom(attrs); attrs = mWindowAttributes; setAccessibilityFocusedHost(null); if (view instanceof RootViewSurfaceTaker) { mSurfaceHolderCallback = ((RootViewSurfaceTaker)view).willYouTakeTheSurface(); Loading Loading @@ -556,6 +558,7 @@ public final class ViewRootImpl implements ViewParent, mInputChannel = null; mFallbackEventHandler.setView(null); unscheduleTraversals(); setAccessibilityFocusedHost(null); throw new RuntimeException("Adding window failed", e); } finally { if (restore) { Loading @@ -575,6 +578,7 @@ public final class ViewRootImpl implements ViewParent, mAdded = false; mFallbackEventHandler.setView(null); unscheduleTraversals(); setAccessibilityFocusedHost(null); switch (res) { case WindowManagerImpl.ADD_BAD_APP_TOKEN: case WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN: Loading Loading @@ -635,8 +639,6 @@ public final class ViewRootImpl implements ViewParent, if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); } setAccessibilityFocusedHost(null); } } } Loading Loading @@ -2543,11 +2545,51 @@ public final class ViewRootImpl implements ViewParent, } void setAccessibilityFocusedHost(View host) { if (mAccessibilityFocusedHost != null && mAccessibilityFocusedVirtualView == null) { // If we have a virtual view with accessibility focus we need // to clear the focus and invalidate the virtual view bounds. if (mAccessibilityFocusedVirtualView != null) { AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView; View focusHost = mAccessibilityFocusedHost; focusHost.clearAccessibilityFocusNoCallbacks(); // Wipe the state of the current accessibility focus since // the call into the provider to clear accessibility focus // will fire an accessibility event which will end up calling // this method and we want to have clean state when this // invocation happens. mAccessibilityFocusedHost = null; mAccessibilityFocusedVirtualView = null; AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider(); if (provider != null) { // Invalidate the area of the cleared accessibility focus. focusNode.getBoundsInParent(mTempRect); focusHost.invalidate(mTempRect); // Clear accessibility focus in the virtual node. final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId( focusNode.getSourceNodeId()); provider.performAction(virtualNodeId, AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); } } if (mAccessibilityFocusedHost != null) { // Clear accessibility focus in the view. mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(); } // Set the new focus host. mAccessibilityFocusedHost = host; mAccessibilityFocusedVirtualView = null; // If the host has a provide find the virtual descendant that has focus. if (mAccessibilityFocusedHost != null) { AccessibilityNodeProvider provider = mAccessibilityFocusedHost.getAccessibilityNodeProvider(); if (provider != null) { mAccessibilityFocusedVirtualView = provider.findAccessibilityFocus(View.NO_ID); return; } } } public void requestChildFocus(View child, View focused) { Loading Loading @@ -2633,6 +2675,8 @@ public final class ViewRootImpl implements ViewParent, destroyHardwareRenderer(); setAccessibilityFocusedHost(null); mView = null; mAttachInfo.mRootView = null; mAttachInfo.mSurface = null; Loading Loading @@ -4608,6 +4652,31 @@ public final class ViewRootImpl implements ViewParent, if (mView == null) { return false; } // Watch for accessibility focus change events from virtual nodes // to keep track of accessibility focus being on a virtual node. final int eventType = event.getEventType(); switch (eventType) { case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: { final long sourceId = event.getSourceNodeId(); // If the event is not from a virtual node we are not interested. final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(sourceId); if (virtualViewId == AccessibilityNodeInfo.UNDEFINED) { break; } final int realViewId = AccessibilityNodeInfo.getAccessibilityViewId(sourceId); View focusHost = mView.findViewByAccessibilityId(realViewId); setAccessibilityFocusedHost(focusHost); } break; case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: { final long sourceId = event.getSourceNodeId(); // If the event is not from a virtual node we are not interested. final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(sourceId); if (virtualViewId == AccessibilityNodeInfo.UNDEFINED) { break; } setAccessibilityFocusedHost(null); } break; } mAccessibilityManager.sendAccessibilityEvent(event); return true; } Loading
core/java/android/widget/NumberPicker.java +242 −12 Original line number Diff line number Diff line Loading @@ -950,6 +950,8 @@ public class NumberPicker extends LinearLayout { provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); mLastHoveredChildVirtualViewId = hoveredVirtualViewId; provider.performAction(hoveredVirtualViewId, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); } break; case MotionEvent.ACTION_HOVER_MOVE: { if (mLastHoveredChildVirtualViewId != hoveredVirtualViewId Loading @@ -960,6 +962,8 @@ public class NumberPicker extends LinearLayout { provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); mLastHoveredChildVirtualViewId = hoveredVirtualViewId; provider.performAction(hoveredVirtualViewId, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); } } break; case MotionEvent.ACTION_HOVER_EXIT: { Loading Loading @@ -1413,9 +1417,16 @@ public class NumberPicker extends LinearLayout { } @Override public void sendAccessibilityEvent(int eventType) { // Do not send accessibility events - we want the user to // perceive this widget as several controls rather as a whole. public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { // We do not want the real descendant to be considered focus search // since it is managed by the accessibility node provider. if ((focusableMode & FOCUSABLES_ACCESSIBILITY) == FOCUSABLES_ACCESSIBILITY) { if (canTakeAccessibilityFocusFromHover() || getAccessibilityNodeProvider() != null) { views.add(this); return; } } super.addFocusables(views, direction, focusableMode); } @Override Loading Loading @@ -2072,7 +2083,12 @@ public class NumberPicker extends LinearLayout { } } /** * Class for managing virtual view tree rooted at this picker. */ class AccessibilityNodeProviderImpl extends AccessibilityNodeProvider { private static final int UNDEFINED = Integer.MIN_VALUE; private static final int VIRTUAL_VIEW_ID_INCREMENT = 1; private static final int VIRTUAL_VIEW_ID_INPUT = 2; Loading @@ -2083,6 +2099,8 @@ public class NumberPicker extends LinearLayout { private final int[] mTempArray = new int[2]; private int mAccessibilityFocusedView = UNDEFINED; @Override public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { switch (virtualViewId) { Loading Loading @@ -2137,6 +2155,25 @@ public class NumberPicker extends LinearLayout { @Override public boolean performAction(int virtualViewId, int action, Bundle arguments) { switch (virtualViewId) { case View.NO_ID: { switch (action) { case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView != virtualViewId) { mAccessibilityFocusedView = virtualViewId; requestAccessibilityFocus(); return true; } } return false; case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView == virtualViewId) { mAccessibilityFocusedView = UNDEFINED; clearAccessibilityFocus(); return true; } return false; } } } break; case VIRTUAL_VIEW_ID_INPUT: { switch (action) { case AccessibilityNodeInfo.ACTION_FOCUS: { Loading @@ -2149,25 +2186,182 @@ public class NumberPicker extends LinearLayout { mInputText.clearFocus(); return true; } return false; } case AccessibilityNodeInfo.ACTION_CLICK: { showSoftInput(); return true; } case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView != virtualViewId) { mAccessibilityFocusedView = virtualViewId; sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); mInputText.invalidate(); return true; } } return false; case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView == virtualViewId) { mAccessibilityFocusedView = UNDEFINED; sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); mInputText.invalidate(); return true; } } return false; default: { return mInputText.performAccessibilityAction(action, arguments); } } } return false; case VIRTUAL_VIEW_ID_INCREMENT: { switch (action) { case AccessibilityNodeInfo.ACTION_CLICK: { NumberPicker.this.changeValueByOne(true); sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_CLICKED); } return true; case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView != virtualViewId) { mAccessibilityFocusedView = virtualViewId; sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); return true; } } return false; case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView == virtualViewId) { mAccessibilityFocusedView = UNDEFINED; sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); return true; } } return false; } } return false; case VIRTUAL_VIEW_ID_DECREMENT: { switch (action) { case AccessibilityNodeInfo.ACTION_CLICK: { final boolean increment = (virtualViewId == VIRTUAL_VIEW_ID_INCREMENT); NumberPicker.this.changeValueByOne(increment); sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_CLICKED); } return true; case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView != virtualViewId) { mAccessibilityFocusedView = virtualViewId; sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); invalidate(0, 0, mRight, mTopSelectionDividerTop); return true; } } return false; case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { if (mAccessibilityFocusedView == virtualViewId) { mAccessibilityFocusedView = UNDEFINED; sendAccessibilityEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); invalidate(0, 0, mRight, mTopSelectionDividerTop); return true; } } return false; } } return false; } return super.performAction(virtualViewId, action, arguments); } @Override public AccessibilityNodeInfo findAccessibilityFocus(int virtualViewId) { return createAccessibilityNodeInfo(mAccessibilityFocusedView); } @Override public AccessibilityNodeInfo accessibilityFocusSearch(int direction, int virtualViewId) { switch (direction) { case View.ACCESSIBILITY_FOCUS_DOWN: case View.ACCESSIBILITY_FOCUS_FORWARD: { switch (mAccessibilityFocusedView) { case UNDEFINED: { return createAccessibilityNodeInfo(View.NO_ID); } case View.NO_ID: { if (hasVirtualDecrementButton()) { return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT); } } //$FALL-THROUGH$ case VIRTUAL_VIEW_ID_DECREMENT: { return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT); } case VIRTUAL_VIEW_ID_INPUT: { if (hasVirtualIncrementButton()) { return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT); } } //$FALL-THROUGH$ case VIRTUAL_VIEW_ID_INCREMENT: { View nextFocus = NumberPicker.this.focusSearch(direction); if (nextFocus != null) { return nextFocus.createAccessibilityNodeInfo(); } return null; } } } break; case View.ACCESSIBILITY_FOCUS_UP: case View.ACCESSIBILITY_FOCUS_BACKWARD: { switch (mAccessibilityFocusedView) { case UNDEFINED: { return createAccessibilityNodeInfo(View.NO_ID); } case View.NO_ID: { if (hasVirtualIncrementButton()) { return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT); } } //$FALL-THROUGH$ case VIRTUAL_VIEW_ID_INCREMENT: { return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT); } case VIRTUAL_VIEW_ID_INPUT: { if (hasVirtualDecrementButton()) { return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT); } } //$FALL-THROUGH$ case VIRTUAL_VIEW_ID_DECREMENT: { View nextFocus = NumberPicker.this.focusSearch(direction); if (nextFocus != null) { return nextFocus.createAccessibilityNodeInfo(); } return null; } } } break; } return super.performAction(virtualViewId, action, arguments); return null; } public void sendAccessibilityEventForVirtualView(int virtualViewId, int eventType) { switch (virtualViewId) { case VIRTUAL_VIEW_ID_DECREMENT: { if (hasVirtualDecrementButton()) { sendAccessibilityEventForVirtualButton(virtualViewId, eventType, getVirtualDecrementButtonText()); } } break; case VIRTUAL_VIEW_ID_INPUT: { sendAccessibilityEventForVirtualText(eventType); } break; case VIRTUAL_VIEW_ID_INCREMENT: { if (hasVirtualIncrementButton()) { sendAccessibilityEventForVirtualButton(virtualViewId, eventType, getVirtualIncrementButtonText()); } } break; } } Loading Loading @@ -2227,8 +2421,13 @@ public class NumberPicker extends LinearLayout { private AccessibilityNodeInfo createAccessibiltyNodeInfoForInputText() { AccessibilityNodeInfo info = mInputText.createAccessibilityNodeInfo(); info.setLongClickable(true); info.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); if (mAccessibilityFocusedView != VIRTUAL_VIEW_ID_INPUT) { info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); } if (mAccessibilityFocusedView == VIRTUAL_VIEW_ID_INPUT) { info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); } return info; } Loading @@ -2252,6 +2451,15 @@ public class NumberPicker extends LinearLayout { getLocationOnScreen(locationOnScreen); boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]); info.setBoundsInScreen(boundsInScreen); if (mAccessibilityFocusedView != virtualViewId) { info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); } if (mAccessibilityFocusedView == virtualViewId) { info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); } info.addAction(AccessibilityNodeInfo.ACTION_CLICK); return info; } Loading @@ -2261,9 +2469,15 @@ public class NumberPicker extends LinearLayout { info.setClassName(NumberPicker.class.getName()); info.setPackageName(mContext.getPackageName()); info.setSource(NumberPicker.this); if (hasVirtualDecrementButton()) { info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_DECREMENT); } info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); if (hasVirtualIncrementButton()) { info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INCREMENT); } info.setParent((View) getParent()); info.setEnabled(NumberPicker.this.isEnabled()); info.setScrollable(true); Loading @@ -2276,9 +2490,25 @@ public class NumberPicker extends LinearLayout { getLocationOnScreen(locationOnScreen); boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]); info.setBoundsInScreen(boundsInScreen); if (mAccessibilityFocusedView != View.NO_ID) { info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); } if (mAccessibilityFocusedView == View.NO_ID) { info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); } return info; } private boolean hasVirtualDecrementButton() { return getWrapSelectorWheel() || getValue() > getMinValue(); } private boolean hasVirtualIncrementButton() { return getWrapSelectorWheel() || getValue() < getMaxValue(); } private String getVirtualDecrementButtonText() { int value = mValue - 1; if (mWrapSelectorWheel) { Loading
core/res/res/layout/time_picker_holo.xml +1 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes