Loading core/java/android/view/InputEventCompatProcessor.java 0 → 100644 +81 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view; import android.content.Context; import android.os.Build; import java.util.ArrayList; import java.util.List; /** * Compatibility processor for InputEvents that allows events to be adjusted before and * after it is sent to the application. * * {@hide} */ public class InputEventCompatProcessor { protected Context mContext; protected int mTargetSdkVersion; /** List of events to be used to return the processed events */ private List<InputEvent> mProcessedEvents; public InputEventCompatProcessor(Context context) { mContext = context; mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; mProcessedEvents = new ArrayList<>(); } /** * Processes the InputEvent for compatibility before it is sent to the app, allowing for the * generation of more than one event if necessary. * * @param e The InputEvent to process * @return The list of adjusted events, or null if no adjustments are needed. Do not keep a * reference to the output as the list is reused. */ public List<InputEvent> processInputEventForCompatibility(InputEvent e) { if (mTargetSdkVersion < Build.VERSION_CODES.M && e instanceof MotionEvent) { mProcessedEvents.clear(); MotionEvent motion = (MotionEvent) e; final int mask = MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY; final int buttonState = motion.getButtonState(); final int compatButtonState = (buttonState & mask) >> 4; if (compatButtonState != 0) { motion.setButtonState(buttonState | compatButtonState); } mProcessedEvents.add(motion); return mProcessedEvents; } return null; } /** * Processes the InputEvent for compatibility before it is finished by calling * InputEventReceiver#finishInputEvent(). * * @param e The InputEvent to process * @return The InputEvent to finish, or null if it should not be finished */ public InputEvent processInputEventBeforeFinish(InputEvent e) { // No changes needed return e; } } core/java/android/view/ViewRootImpl.java +61 −16 Original line number Diff line number Diff line Loading @@ -124,6 +124,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.concurrent.CountDownLatch; Loading Loading @@ -543,6 +544,8 @@ public final class ViewRootImpl implements ViewParent, private boolean mNeedsRendererSetup; private final InputEventCompatProcessor mInputCompatProcessor; /** * Consistency verifier for debugging purposes. */ Loading Loading @@ -598,6 +601,25 @@ public final class ViewRootImpl implements ViewParent, mChoreographer = Choreographer.getInstance(); mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); String processorOverrideName = context.getResources().getString( R.string.config_inputEventCompatProcessorOverrideClassName); if (processorOverrideName.isEmpty()) { // No compatibility processor override, using default. mInputCompatProcessor = new InputEventCompatProcessor(context); } else { InputEventCompatProcessor compatProcessor = null; try { final Class<? extends InputEventCompatProcessor> klass = (Class<? extends InputEventCompatProcessor>) Class.forName( processorOverrideName); compatProcessor = klass.getConstructor(Context.class).newInstance(context); } catch (Exception e) { Log.e(TAG, "Unable to create the InputEventCompatProcessor. ", e); } finally { mInputCompatProcessor = compatProcessor; } } if (!sCompatibilityDone) { sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P; Loading Loading @@ -7166,6 +7188,7 @@ public final class ViewRootImpl implements ViewParent, public static final int FLAG_FINISHED_HANDLED = 1 << 3; public static final int FLAG_RESYNTHESIZED = 1 << 4; public static final int FLAG_UNHANDLED = 1 << 5; public static final int FLAG_MODIFIED_FOR_COMPATIBILITY = 1 << 6; public QueuedInputEvent mNext; Loading Loading @@ -7258,7 +7281,6 @@ public final class ViewRootImpl implements ViewParent, @UnsupportedAppUsage void enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) { adjustInputEventForCompatibility(event); QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); // Always enqueue the input event in order, regardless of its time stamp. Loading Loading @@ -7361,7 +7383,22 @@ public final class ViewRootImpl implements ViewParent, if (q.mReceiver != null) { boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0; boolean modified = (q.mFlags & QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY) != 0; if (modified) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventBeforeFinish"); InputEvent processedEvent; try { processedEvent = mInputCompatProcessor.processInputEventBeforeFinish(q.mEvent); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } if (processedEvent != null) { q.mReceiver.finishInputEvent(processedEvent, handled); } } else { q.mReceiver.finishInputEvent(q.mEvent, handled); } } else { q.mEvent.recycleIfNeededAfterDispatch(); } Loading @@ -7369,19 +7406,6 @@ public final class ViewRootImpl implements ViewParent, recycleQueuedInputEvent(q); } private void adjustInputEventForCompatibility(InputEvent e) { if (mTargetSdkVersion < Build.VERSION_CODES.M && e instanceof MotionEvent) { MotionEvent motion = (MotionEvent) e; final int mask = MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY; final int buttonState = motion.getButtonState(); final int compatButtonState = (buttonState & mask) >> 4; if (compatButtonState != 0) { motion.setButtonState(buttonState | compatButtonState); } } } static boolean isTerminalInputEvent(InputEvent event) { if (event instanceof KeyEvent) { final KeyEvent keyEvent = (KeyEvent)event; Loading Loading @@ -7452,8 +7476,29 @@ public final class ViewRootImpl implements ViewParent, @Override public void onInputEvent(InputEvent event) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility"); List<InputEvent> processedEvents; try { processedEvents = mInputCompatProcessor.processInputEventForCompatibility(event); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } if (processedEvents != null) { if (processedEvents.isEmpty()) { // InputEvent consumed by mInputCompatProcessor finishInputEvent(event, true); } else { for (int i = 0; i < processedEvents.size(); i++) { enqueueInputEvent( processedEvents.get(i), this, QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true); } } } else { enqueueInputEvent(event, this, 0, true); } } @Override public void onBatchedInputEventPending() { Loading core/res/res/values/config.xml +5 −0 Original line number Diff line number Diff line Loading @@ -3597,4 +3597,9 @@ <!-- Component name for default assistant on this device --> <string name="config_defaultAssistantComponentName">#+UNSET</string> <!-- Class name for the InputEvent compatibility processor override. Empty string means use the default compatibility processor (android.view.InputEventCompatProcessor). --> <string name="config_inputEventCompatProcessorOverrideClassName" translatable="false"></string> </resources> core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -302,6 +302,7 @@ <java-symbol type="bool" name="config_enableWallpaperService" /> <java-symbol type="bool" name="config_checkWallpaperAtBoot" /> <java-symbol type="string" name="config_wallpaperManagerServiceName" /> <java-symbol type="string" name="config_inputEventCompatProcessorOverrideClassName" /> <java-symbol type="bool" name="config_enableUpdateableTimeZoneRules" /> <java-symbol type="bool" name="config_timeZoneRulesUpdateTrackingEnabled" /> <java-symbol type="string" name="config_timeZoneRulesUpdaterPackage" /> Loading Loading
core/java/android/view/InputEventCompatProcessor.java 0 → 100644 +81 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view; import android.content.Context; import android.os.Build; import java.util.ArrayList; import java.util.List; /** * Compatibility processor for InputEvents that allows events to be adjusted before and * after it is sent to the application. * * {@hide} */ public class InputEventCompatProcessor { protected Context mContext; protected int mTargetSdkVersion; /** List of events to be used to return the processed events */ private List<InputEvent> mProcessedEvents; public InputEventCompatProcessor(Context context) { mContext = context; mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; mProcessedEvents = new ArrayList<>(); } /** * Processes the InputEvent for compatibility before it is sent to the app, allowing for the * generation of more than one event if necessary. * * @param e The InputEvent to process * @return The list of adjusted events, or null if no adjustments are needed. Do not keep a * reference to the output as the list is reused. */ public List<InputEvent> processInputEventForCompatibility(InputEvent e) { if (mTargetSdkVersion < Build.VERSION_CODES.M && e instanceof MotionEvent) { mProcessedEvents.clear(); MotionEvent motion = (MotionEvent) e; final int mask = MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY; final int buttonState = motion.getButtonState(); final int compatButtonState = (buttonState & mask) >> 4; if (compatButtonState != 0) { motion.setButtonState(buttonState | compatButtonState); } mProcessedEvents.add(motion); return mProcessedEvents; } return null; } /** * Processes the InputEvent for compatibility before it is finished by calling * InputEventReceiver#finishInputEvent(). * * @param e The InputEvent to process * @return The InputEvent to finish, or null if it should not be finished */ public InputEvent processInputEventBeforeFinish(InputEvent e) { // No changes needed return e; } }
core/java/android/view/ViewRootImpl.java +61 −16 Original line number Diff line number Diff line Loading @@ -124,6 +124,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.concurrent.CountDownLatch; Loading Loading @@ -543,6 +544,8 @@ public final class ViewRootImpl implements ViewParent, private boolean mNeedsRendererSetup; private final InputEventCompatProcessor mInputCompatProcessor; /** * Consistency verifier for debugging purposes. */ Loading Loading @@ -598,6 +601,25 @@ public final class ViewRootImpl implements ViewParent, mChoreographer = Choreographer.getInstance(); mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); String processorOverrideName = context.getResources().getString( R.string.config_inputEventCompatProcessorOverrideClassName); if (processorOverrideName.isEmpty()) { // No compatibility processor override, using default. mInputCompatProcessor = new InputEventCompatProcessor(context); } else { InputEventCompatProcessor compatProcessor = null; try { final Class<? extends InputEventCompatProcessor> klass = (Class<? extends InputEventCompatProcessor>) Class.forName( processorOverrideName); compatProcessor = klass.getConstructor(Context.class).newInstance(context); } catch (Exception e) { Log.e(TAG, "Unable to create the InputEventCompatProcessor. ", e); } finally { mInputCompatProcessor = compatProcessor; } } if (!sCompatibilityDone) { sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P; Loading Loading @@ -7166,6 +7188,7 @@ public final class ViewRootImpl implements ViewParent, public static final int FLAG_FINISHED_HANDLED = 1 << 3; public static final int FLAG_RESYNTHESIZED = 1 << 4; public static final int FLAG_UNHANDLED = 1 << 5; public static final int FLAG_MODIFIED_FOR_COMPATIBILITY = 1 << 6; public QueuedInputEvent mNext; Loading Loading @@ -7258,7 +7281,6 @@ public final class ViewRootImpl implements ViewParent, @UnsupportedAppUsage void enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) { adjustInputEventForCompatibility(event); QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); // Always enqueue the input event in order, regardless of its time stamp. Loading Loading @@ -7361,7 +7383,22 @@ public final class ViewRootImpl implements ViewParent, if (q.mReceiver != null) { boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0; boolean modified = (q.mFlags & QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY) != 0; if (modified) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventBeforeFinish"); InputEvent processedEvent; try { processedEvent = mInputCompatProcessor.processInputEventBeforeFinish(q.mEvent); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } if (processedEvent != null) { q.mReceiver.finishInputEvent(processedEvent, handled); } } else { q.mReceiver.finishInputEvent(q.mEvent, handled); } } else { q.mEvent.recycleIfNeededAfterDispatch(); } Loading @@ -7369,19 +7406,6 @@ public final class ViewRootImpl implements ViewParent, recycleQueuedInputEvent(q); } private void adjustInputEventForCompatibility(InputEvent e) { if (mTargetSdkVersion < Build.VERSION_CODES.M && e instanceof MotionEvent) { MotionEvent motion = (MotionEvent) e; final int mask = MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY; final int buttonState = motion.getButtonState(); final int compatButtonState = (buttonState & mask) >> 4; if (compatButtonState != 0) { motion.setButtonState(buttonState | compatButtonState); } } } static boolean isTerminalInputEvent(InputEvent event) { if (event instanceof KeyEvent) { final KeyEvent keyEvent = (KeyEvent)event; Loading Loading @@ -7452,8 +7476,29 @@ public final class ViewRootImpl implements ViewParent, @Override public void onInputEvent(InputEvent event) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility"); List<InputEvent> processedEvents; try { processedEvents = mInputCompatProcessor.processInputEventForCompatibility(event); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } if (processedEvents != null) { if (processedEvents.isEmpty()) { // InputEvent consumed by mInputCompatProcessor finishInputEvent(event, true); } else { for (int i = 0; i < processedEvents.size(); i++) { enqueueInputEvent( processedEvents.get(i), this, QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true); } } } else { enqueueInputEvent(event, this, 0, true); } } @Override public void onBatchedInputEventPending() { Loading
core/res/res/values/config.xml +5 −0 Original line number Diff line number Diff line Loading @@ -3597,4 +3597,9 @@ <!-- Component name for default assistant on this device --> <string name="config_defaultAssistantComponentName">#+UNSET</string> <!-- Class name for the InputEvent compatibility processor override. Empty string means use the default compatibility processor (android.view.InputEventCompatProcessor). --> <string name="config_inputEventCompatProcessorOverrideClassName" translatable="false"></string> </resources>
core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -302,6 +302,7 @@ <java-symbol type="bool" name="config_enableWallpaperService" /> <java-symbol type="bool" name="config_checkWallpaperAtBoot" /> <java-symbol type="string" name="config_wallpaperManagerServiceName" /> <java-symbol type="string" name="config_inputEventCompatProcessorOverrideClassName" /> <java-symbol type="bool" name="config_enableUpdateableTimeZoneRules" /> <java-symbol type="bool" name="config_timeZoneRulesUpdateTrackingEnabled" /> <java-symbol type="string" name="config_timeZoneRulesUpdaterPackage" /> Loading