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

Commit 88836ce6 authored by Evan Rosky's avatar Evan Rosky Committed by android-build-merger
Browse files

Merge "Renamed KeyFallbackEvent to UnhandledKeyEvent and exposed dispatch"...

Merge "Renamed KeyFallbackEvent to UnhandledKeyEvent and exposed dispatch" into pi-dev am: e1059d9f
am: 1334492e

Change-Id: Ic2eb0d1c4ea9d7b7ff4c31ff97523225de128aa3
parents c431926a 1334492e
Loading
Loading
Loading
Loading
+6 −7
Original line number Diff line number Diff line
@@ -47305,10 +47305,10 @@ package android.view {
    method public void addExtraDataToAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
    method public void addFocusables(java.util.ArrayList<android.view.View>, int);
    method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
    method public void addKeyFallbackListener(android.view.View.OnKeyFallbackListener);
    method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
    method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
    method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
    method public void addOnUnhandledKeyEventListener(android.view.View.OnUnhandledKeyEventListener);
    method public void addTouchables(java.util.ArrayList<android.view.View>);
    method public android.view.ViewPropertyAnimator animate();
    method public void announceForAccessibility(java.lang.CharSequence);
@@ -47646,7 +47646,6 @@ package android.view {
    method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
    method public void onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo);
    method public boolean onKeyDown(int, android.view.KeyEvent);
    method public boolean onKeyFallback(android.view.KeyEvent);
    method public boolean onKeyLongPress(int, android.view.KeyEvent);
    method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
    method public boolean onKeyPreIme(int, android.view.KeyEvent);
@@ -47700,9 +47699,9 @@ package android.view {
    method public void refreshDrawableState();
    method public void releasePointerCapture();
    method public boolean removeCallbacks(java.lang.Runnable);
    method public void removeKeyFallbackListener(android.view.View.OnKeyFallbackListener);
    method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
    method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
    method public void removeOnUnhandledKeyEventListener(android.view.View.OnUnhandledKeyEventListener);
    method public void requestApplyInsets();
    method public deprecated void requestFitSystemWindows();
    method public final boolean requestFocus();
@@ -48126,10 +48125,6 @@ package android.view {
    method public abstract boolean onHover(android.view.View, android.view.MotionEvent);
  }
  public static abstract interface View.OnKeyFallbackListener {
    method public abstract boolean onKeyFallback(android.view.View, android.view.KeyEvent);
  }
  public static abstract interface View.OnKeyListener {
    method public abstract boolean onKey(android.view.View, int, android.view.KeyEvent);
  }
@@ -48154,6 +48149,10 @@ package android.view {
    method public abstract boolean onTouch(android.view.View, android.view.MotionEvent);
  }
  public static abstract interface View.OnUnhandledKeyEventListener {
    method public abstract boolean onUnhandledKeyEvent(android.view.View, android.view.KeyEvent);
  }
  public final class ViewAnimationUtils {
    method public static android.animation.Animator createCircularReveal(android.view.View, int, int, float, float);
  }
+66 −42
Original line number Diff line number Diff line
@@ -4320,7 +4320,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        OnCapturedPointerListener mOnCapturedPointerListener;
        private ArrayList<OnKeyFallbackListener> mKeyFallbackListeners;
        private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners;
    }
    ListenerInfo mListenerInfo;
@@ -25882,26 +25882,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    }
    /**
     * Interface definition for a callback to be invoked when a hardware key event is
     * dispatched to this view during the fallback phase. This means no view in the hierarchy
     * has handled this event.
     * Interface definition for a callback to be invoked when a hardware key event hasn't
     * been handled by the view hierarchy.
     */
    public interface OnKeyFallbackListener {
    public interface OnUnhandledKeyEventListener {
        /**
         * Called when a hardware key is dispatched to a view in the fallback phase. This allows
         * listeners to respond to events after the view hierarchy has had a chance to respond.
         * <p>Key presses in software keyboards will generally NOT trigger this method,
         * although some may elect to do so in some situations. Do not assume a
         * software input method has to be key-based; even if it is, it may use key presses
         * in a different way than you expect, so there is no way to reliably catch soft
         * input key presses.
         * Called when a hardware key is dispatched to a view after being unhandled during normal
         * {@link KeyEvent} dispatch.
         *
         * @param v The view the key has been dispatched to.
         * @param event The KeyEvent object containing full information about
         *        the event.
         * @return True if the listener has consumed the event, false otherwise.
         * @param event The KeyEvent object containing information about the event.
         * @return {@code true} if the listener has consumed the event, {@code false} otherwise.
         */
        boolean onKeyFallback(View v, KeyEvent event);
        boolean onUnhandledKeyEvent(View v, KeyEvent event);
    }
    /**
@@ -27600,21 +27593,36 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        return sUseDefaultFocusHighlight;
    }
    /**
     * Dispatch a previously unhandled {@link KeyEvent} to this view. Unlike normal key dispatch,
     * this dispatches to ALL child views until it is consumed. The dispatch order is z-order
     * (visually on-top views first).
     *
     * @param evt the previously unhandled {@link KeyEvent}.
     * @return the {@link View} which consumed the event or {@code null} if not consumed.
     */
    View dispatchUnhandledKeyEvent(KeyEvent evt) {
        if (onUnhandledKeyEvent(evt)) {
            return this;
        }
        return null;
    }
    /**
     * Allows this view to handle {@link KeyEvent}s which weren't handled by normal dispatch. This
     * occurs after the normal view hierarchy dispatch, but before the window callback. By default,
     * this will dispatch into all the listeners registered via
     * {@link #addKeyFallbackListener(OnKeyFallbackListener)} in last-in-first-out order (most
     * recently added will receive events first).
     * {@link #addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener)} in last-in-first-out
     * order (most recently added will receive events first).
     *
     * @param event A not-previously-handled event.
     * @param event An unhandled event.
     * @return {@code true} if the event was handled, {@code false} otherwise.
     * @see #addKeyFallbackListener
     * @see #addOnUnhandledKeyEventListener
     */
    public boolean onKeyFallback(@NonNull KeyEvent event) {
        if (mListenerInfo != null && mListenerInfo.mKeyFallbackListeners != null) {
            for (int i = mListenerInfo.mKeyFallbackListeners.size() - 1; i >= 0; --i) {
                if (mListenerInfo.mKeyFallbackListeners.get(i).onKeyFallback(this, event)) {
    boolean onUnhandledKeyEvent(@NonNull KeyEvent event) {
        if (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null) {
            for (int i = mListenerInfo.mUnhandledKeyListeners.size() - 1; i >= 0; --i) {
                if (mListenerInfo.mUnhandledKeyListeners.get(i).onUnhandledKeyEvent(this, event)) {
                    return true;
                }
            }
@@ -27622,31 +27630,47 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        return false;
    }
    boolean hasUnhandledKeyListener() {
        return (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null
                && !mListenerInfo.mUnhandledKeyListeners.isEmpty());
    }
    /**
     * Adds a listener which will receive unhandled {@link KeyEvent}s.
     * @param listener the receiver of fallback {@link KeyEvent}s.
     * @see #onKeyFallback(KeyEvent)
     * Adds a listener which will receive unhandled {@link KeyEvent}s. This must be called on the
     * UI thread.
     *
     * @param listener a receiver of unhandled {@link KeyEvent}s.
     * @see #removeOnUnhandledKeyEventListener
     */
    public void addKeyFallbackListener(OnKeyFallbackListener listener) {
        ArrayList<OnKeyFallbackListener> fallbacks = getListenerInfo().mKeyFallbackListeners;
        if (fallbacks == null) {
            fallbacks = new ArrayList<>();
            getListenerInfo().mKeyFallbackListeners = fallbacks;
    public void addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) {
        ArrayList<OnUnhandledKeyEventListener> listeners = getListenerInfo().mUnhandledKeyListeners;
        if (listeners == null) {
            listeners = new ArrayList<>();
            getListenerInfo().mUnhandledKeyListeners = listeners;
        }
        listeners.add(listener);
        if (listeners.size() == 1 && mParent instanceof ViewGroup) {
            ((ViewGroup) mParent).incrementChildUnhandledKeyListeners();
        }
        fallbacks.add(listener);
    }
    /**
     * Removes a listener which will receive unhandled {@link KeyEvent}s.
     * @param listener the receiver of fallback {@link KeyEvent}s.
     * @see #onKeyFallback(KeyEvent)
     * Removes a listener which will receive unhandled {@link KeyEvent}s. This must be called on the
     * UI thread.
     *
     * @param listener a receiver of unhandled {@link KeyEvent}s.
     * @see #addOnUnhandledKeyEventListener
     */
    public void removeKeyFallbackListener(OnKeyFallbackListener listener) {
    public void removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) {
        if (mListenerInfo != null) {
            if (mListenerInfo.mKeyFallbackListeners != null) {
                mListenerInfo.mKeyFallbackListeners.remove(listener);
                if (mListenerInfo.mKeyFallbackListeners.isEmpty()) {
                    mListenerInfo.mKeyFallbackListeners = null;
            if (mListenerInfo.mUnhandledKeyListeners != null
                    && !mListenerInfo.mUnhandledKeyListeners.isEmpty()) {
                mListenerInfo.mUnhandledKeyListeners.remove(listener);
                if (mListenerInfo.mUnhandledKeyListeners.isEmpty()) {
                    mListenerInfo.mUnhandledKeyListeners = null;
                    if (mParent instanceof ViewGroup) {
                        ((ViewGroup) mParent).decrementChildUnhandledKeyListeners();
                    }
                }
            }
        }
+68 −0
Original line number Diff line number Diff line
@@ -583,6 +583,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    private List<Integer> mTransientIndices = null;
    private List<View> mTransientViews = null;

    /**
     * Keeps track of how many child views have UnhandledKeyEventListeners. This should only be
     * updated on the UI thread so shouldn't require explicit synchronization.
     */
    int mChildUnhandledKeyListeners = 0;

    /**
     * Empty ActionMode used as a sentinel in recursive entries to startActionModeForChild.
@@ -5055,6 +5060,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            child.assignParent(this);
        } else {
            child.mParent = this;
            if (child.hasUnhandledKeyListener()) {
                incrementChildUnhandledKeyListeners();
            }
        }

        final boolean childHasFocus = child.hasFocus();
@@ -5359,6 +5367,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager

        removeFromArray(index);

        if (view.hasUnhandledKeyListener()) {
            decrementChildUnhandledKeyListeners();
        }

        if (view == mDefaultFocus) {
            clearDefaultFocus(view);
        }
@@ -7537,6 +7549,62 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        }
    }

    @Override
    boolean hasUnhandledKeyListener() {
        return (mChildUnhandledKeyListeners > 0) || super.hasUnhandledKeyListener();
    }

    void incrementChildUnhandledKeyListeners() {
        mChildUnhandledKeyListeners += 1;
        if (mChildUnhandledKeyListeners == 1) {
            if (mParent instanceof ViewGroup) {
                ((ViewGroup) mParent).incrementChildUnhandledKeyListeners();
            }
        }
    }

    void decrementChildUnhandledKeyListeners() {
        mChildUnhandledKeyListeners -= 1;
        if (mChildUnhandledKeyListeners == 0) {
            if (mParent instanceof ViewGroup) {
                ((ViewGroup) mParent).decrementChildUnhandledKeyListeners();
            }
        }
    }

    @Override
    View dispatchUnhandledKeyEvent(KeyEvent evt) {
        if (!hasUnhandledKeyListener()) {
            return null;
        }
        ArrayList<View> orderedViews = buildOrderedChildList();
        if (orderedViews != null) {
            try {
                for (int i = orderedViews.size() - 1; i >= 0; --i) {
                    View v = orderedViews.get(i);
                    View consumer = v.dispatchUnhandledKeyEvent(evt);
                    if (consumer != null) {
                        return consumer;
                    }
                }
            } finally {
                orderedViews.clear();
            }
        } else {
            for (int i = getChildCount() - 1; i >= 0; --i) {
                View v = getChildAt(i);
                View consumer = v.dispatchUnhandledKeyEvent(evt);
                if (consumer != null) {
                    return consumer;
                }
            }
        }
        if (onUnhandledKeyEvent(evt)) {
            return this;
        }
        return null;
    }

    /**
     * LayoutParams are used by views to tell their parents how they want to be
     * laid out. See
+21 −50
Original line number Diff line number Diff line
@@ -380,7 +380,7 @@ public final class ViewRootImpl implements ViewParent,
    InputStage mFirstPostImeInputStage;
    InputStage mSyntheticInputStage;

    private final KeyFallbackManager mKeyFallbackManager = new KeyFallbackManager();
    private final UnhandledKeyManager mUnhandledKeyManager = new UnhandledKeyManager();

    boolean mWindowAttributesChanged = false;
    int mWindowAttributesChangesFlag = 0;
@@ -4975,10 +4975,10 @@ public final class ViewRootImpl implements ViewParent,
        private int processKeyEvent(QueuedInputEvent q) {
            final KeyEvent event = (KeyEvent)q.mEvent;

            mKeyFallbackManager.mDispatched = false;
            mUnhandledKeyManager.mDispatched = false;

            if (mKeyFallbackManager.hasFocus()
                    && mKeyFallbackManager.dispatchUnique(mView, event)) {
            if (mUnhandledKeyManager.hasFocus()
                    && mUnhandledKeyManager.dispatchUnique(mView, event)) {
                return FINISH_HANDLED;
            }

@@ -4991,7 +4991,7 @@ public final class ViewRootImpl implements ViewParent,
                return FINISH_NOT_HANDLED;
            }

            if (mKeyFallbackManager.dispatchUnique(mView, event)) {
            if (mUnhandledKeyManager.dispatchUnique(mView, event)) {
                return FINISH_HANDLED;
            }

@@ -7798,7 +7798,7 @@ public final class ViewRootImpl implements ViewParent,
     * @return {@code true} if the event was handled, {@code false} otherwise.
     */
    public boolean dispatchKeyFallbackEvent(KeyEvent event) {
        return mKeyFallbackManager.dispatch(mView, event);
        return mUnhandledKeyManager.dispatch(mView, event);
    }

    class TakenSurfaceHolder extends BaseSurfaceHolder {
@@ -8374,18 +8374,17 @@ public final class ViewRootImpl implements ViewParent,
        }
    }

    private static class KeyFallbackManager {
    private static class UnhandledKeyManager {

        // This is used to ensure that key-fallback events are only dispatched once. We attempt
        // This is used to ensure that unhandled events are only dispatched once. We attempt
        // to dispatch more than once in order to achieve a certain order. Specifically, if we
        // are in an Activity or Dialog (and have a Window.Callback), the keyfallback events should
        // are in an Activity or Dialog (and have a Window.Callback), the unhandled events should
        // be dispatched after the view hierarchy, but before the Activity. However, if we aren't
        // in an activity, we still want key fallbacks to be dispatched.
        // in an activity, we still want unhandled keys to be dispatched.
        boolean mDispatched = false;

        SparseBooleanArray mCapturedKeys = new SparseBooleanArray();
        WeakReference<View> mFallbackReceiver = null;
        int mVisitCount = 0;
        WeakReference<View> mCurrentReceiver = null;

        private void updateCaptureState(KeyEvent event) {
            if (event.getAction() == KeyEvent.ACTION_DOWN) {
@@ -8402,56 +8401,28 @@ public final class ViewRootImpl implements ViewParent,

            updateCaptureState(event);

            if (mFallbackReceiver != null) {
                View target = mFallbackReceiver.get();
            if (mCurrentReceiver != null) {
                View target = mCurrentReceiver.get();
                if (mCapturedKeys.size() == 0) {
                    mFallbackReceiver = null;
                    mCurrentReceiver = null;
                }
                if (target != null && target.isAttachedToWindow()) {
                    return target.onKeyFallback(event);
                    target.onUnhandledKeyEvent(event);
                }
                // consume anyways so that we don't feed uncaptured key events to other views
                return true;
            }

            boolean result = dispatchInZOrder(root, event);
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            return result;
        }

        private boolean dispatchInZOrder(View view, KeyEvent evt) {
            if (view instanceof ViewGroup) {
                ViewGroup vg = (ViewGroup) view;
                ArrayList<View> orderedViews = vg.buildOrderedChildList();
                if (orderedViews != null) {
                    try {
                        for (int i = orderedViews.size() - 1; i >= 0; --i) {
                            View v = orderedViews.get(i);
                            if (dispatchInZOrder(v, evt)) {
                                return true;
                            }
            View consumer = root.dispatchUnhandledKeyEvent(event);
            if (consumer != null) {
                mCurrentReceiver = new WeakReference<>(consumer);
            }
                    } finally {
                        orderedViews.clear();
                    }
                } else {
                    for (int i = vg.getChildCount() - 1; i >= 0; --i) {
                        View v = vg.getChildAt(i);
                        if (dispatchInZOrder(v, evt)) {
                            return true;
                        }
                    }
                }
            }
            if (view.onKeyFallback(evt)) {
                mFallbackReceiver = new WeakReference<>(view);
                return true;
            }
            return false;
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            return consumer != null;
        }

        boolean hasFocus() {
            return mFallbackReceiver != null;
            return mCurrentReceiver != null;
        }

        boolean dispatchUnique(View root, KeyEvent event) {