Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec6cf184 authored by Alan Viverette's avatar Alan Viverette
Browse files

Manage accessibility focus during PhoneWindow save and restore

Bug: 21403390
Change-Id: Ia474a54b55ba6e0309dda58939daa47b93a7dccb
parent c2f61b77
Loading
Loading
Loading
Loading
+59 −11
Original line number Diff line number Diff line
@@ -115,6 +115,8 @@ import android.util.SparseArray;
import android.util.TypedValue;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -2000,6 +2002,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
    }

    static private final String FOCUSED_ID_TAG = "android:focusedViewId";
    static private final String ACCESSIBILITY_FOCUSED_ID_TAG = "android:accessibilityFocusedViewId";
    static private final String ACCESSIBILITY_FOCUSED_VIRTUAL_ID_TAG =
            "android:accessibilityFocusedVirtualViewId";
    static private final String VIEWS_TAG = "android:views";
    static private final String PANELS_TAG = "android:Panels";
    static private final String ACTION_BAR_TAG = "android:ActionBar";
@@ -2016,16 +2021,25 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
        mContentParent.saveHierarchyState(states);
        outState.putSparseParcelableArray(VIEWS_TAG, states);

        // save the focused view id
        View focusedView = mContentParent.findFocus();
        if (focusedView != null) {
            if (focusedView.getId() != View.NO_ID) {
        // Save the focused view ID.
        final View focusedView = mContentParent.findFocus();
        if (focusedView != null && focusedView.getId() != View.NO_ID) {
            outState.putInt(FOCUSED_ID_TAG, focusedView.getId());
            } else {
                if (false) {
                    Log.d(TAG, "couldn't save which view has focus because the focused view "
                            + focusedView + " has no id.");
        }

        // Save the accessibility focused view ID.
        final ViewRootImpl viewRootImpl = mContentParent.getViewRootImpl();
        final View accessFocusHost = viewRootImpl.getAccessibilityFocusedHost();
        if (accessFocusHost != null && accessFocusHost.getId() != View.NO_ID) {
            outState.putInt(ACCESSIBILITY_FOCUSED_ID_TAG, accessFocusHost.getId());

            // If we have a focused virtual node ID, save that too.
            final AccessibilityNodeInfo accessFocusedNode =
                    viewRootImpl.getAccessibilityFocusedVirtualView();
            if (accessFocusedNode != null) {
                final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
                        accessFocusedNode.getSourceNodeId());
                outState.putInt(ACCESSIBILITY_FOCUSED_VIRTUAL_ID_TAG, virtualNodeId);
            }
        }

@@ -2071,7 +2085,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
            }
        }

        // restore the panels
        // Restore the accessibility focused view.
        final int accessFocusHostViewId = savedInstanceState.getInt(
                ACCESSIBILITY_FOCUSED_ID_TAG, View.NO_ID);
        final int accessFocusVirtualViewId = savedInstanceState.getInt(
                ACCESSIBILITY_FOCUSED_VIRTUAL_ID_TAG, AccessibilityNodeInfo.UNDEFINED_ITEM_ID);
        tryRestoreAccessibilityFocus(accessFocusHostViewId, accessFocusVirtualViewId);

        // Restore the panels.
        SparseArray<Parcelable> panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG);
        if (panelStates != null) {
            restorePanelState(panelStates);
@@ -2090,6 +2111,33 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
        }
    }

    private void tryRestoreAccessibilityFocus(int hostViewId, int virtualViewId) {
        if (hostViewId != View.NO_ID) {
            final View needsAccessFocus = mContentParent.findViewById(hostViewId);
            if (needsAccessFocus != null) {
                if (!tryFocusingVirtualView(needsAccessFocus, virtualViewId)
                        && !needsAccessFocus.requestAccessibilityFocus()) {
                    Log.w(TAG, "Failed to restore focus to previously accessibility"
                            + " focused view with id " + hostViewId);
                }
            } else {
                Log.w(TAG, "Previously accessibility focused view reported id " + hostViewId
                        + " during save, but can't be found during restore.");
            }
        }
    }

    private boolean tryFocusingVirtualView(View host, int virtualViewId) {
        if (virtualViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
            final AccessibilityNodeProvider nodeProvider = host.getAccessibilityNodeProvider();
            if (nodeProvider != null) {
                return nodeProvider.performAction(virtualViewId,
                        AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
            }
        }
        return false;
    }

    /**
     * Invoked when the panels should freeze their state.
     *