diff options
Diffstat (limited to 'quickstep')
6 files changed, 134 insertions, 9 deletions
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java index e20ef5259..2c919b3c1 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java @@ -296,10 +296,6 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut if (sysUiProxy == null) { return null; } - if (SysUINavigationMode.getMode(activity) == SysUINavigationMode.Mode.NO_BUTTON) { - // TODO(b/130225926): Temporarily disable pinning while gesture nav is enabled - return null; - } if (!ActivityManagerWrapper.getInstance().isScreenPinningEnabled()) { return null; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index cad607423..128fd45fe 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -72,6 +72,7 @@ import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer; import com.android.quickstep.inputconsumers.InputConsumer; import com.android.quickstep.inputconsumers.OtherActivityInputConsumer; import com.android.quickstep.inputconsumers.OverviewInputConsumer; +import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -466,6 +467,12 @@ public class TouchInteractionService extends Service implements mInputMonitorCompat); } + if (ActivityManagerWrapper.getInstance().isScreenPinningActive()) { + // Note: we only allow accessibility to wrap this, and it replaces the previous + // base input consumer (which should be NO_OP anyway since topTaskLocked == true). + base = new ScreenPinnedInputConsumer(this, mISystemUiProxy, activityControl); + } + if ((mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0) { base = new AccessibilityInputConsumer(this, mISystemUiProxy, (mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0, base, diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java index 3593d162d..2e8880dde 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java @@ -30,6 +30,7 @@ public interface InputConsumer { int TYPE_ASSISTANT = 1 << 3; int TYPE_DEVICE_LOCKED = 1 << 4; int TYPE_ACCESSIBILITY = 1 << 5; + int TYPE_SCREEN_PINNED = 1 << 6; InputConsumer NO_OP = () -> TYPE_NO_OP; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java new file mode 100644 index 000000000..a0e20f2cd --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2019 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 com.android.quickstep.inputconsumers; + +import android.content.Context; +import android.os.RemoteException; +import android.util.Log; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; + +import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.R; +import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.util.MotionPauseDetector; +import com.android.systemui.shared.recents.ISystemUiProxy; + +/** + * An input consumer that detects swipe up and hold to exit screen pinning mode. + */ +public class ScreenPinnedInputConsumer implements InputConsumer { + + private static final String TAG = "ScreenPinnedConsumer"; + + private final float mMotionPauseMinDisplacement; + private final MotionPauseDetector mMotionPauseDetector; + + private float mTouchDownY; + + public ScreenPinnedInputConsumer(Context context, ISystemUiProxy sysuiProxy, + ActivityControlHelper activityControl) { + mMotionPauseMinDisplacement = context.getResources().getDimension( + R.dimen.motion_pause_detector_min_displacement_from_app); + mMotionPauseDetector = new MotionPauseDetector(context, true /* makePauseHarderToTrigger*/); + mMotionPauseDetector.setOnMotionPauseListener(isPaused -> { + if (isPaused) { + try { + sysuiProxy.stopScreenPinning(); + BaseDraggingActivity launcherActivity = activityControl.getCreatedActivity(); + if (launcherActivity != null) { + launcherActivity.getRootView().performHapticFeedback( + HapticFeedbackConstants.LONG_PRESS, + HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + } + mMotionPauseDetector.clear(); + } catch (RemoteException e) { + Log.e(TAG, "Unable to stop screen pinning ", e); + } + } + }); + } + + @Override + public int getType() { + return TYPE_SCREEN_PINNED; + } + + @Override + public void onMotionEvent(MotionEvent ev) { + float y = ev.getY(); + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + mTouchDownY = y; + break; + case MotionEvent.ACTION_MOVE: + float displacement = mTouchDownY - y; + mMotionPauseDetector.setDisallowPause(displacement < mMotionPauseMinDisplacement); + mMotionPauseDetector.addPosition(y, ev.getEventTime()); + break; + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + mMotionPauseDetector.clear(); + break; + } + } +} diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index 32f312fdb..82d1aa672 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -36,6 +36,7 @@ <!-- These speeds are in dp / ms --> <dimen name="motion_pause_detector_speed_very_slow">0.0285dp</dimen> + <dimen name="motion_pause_detector_speed_slow">0.15dp</dimen> <dimen name="motion_pause_detector_speed_somewhat_fast">0.285dp</dimen> <dimen name="motion_pause_detector_speed_fast">0.5dp</dimen> <dimen name="motion_pause_detector_min_displacement_from_app">36dp</dimen> diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java index f58f0d485..893c05356 100644 --- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java +++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java @@ -35,10 +35,18 @@ public class MotionPauseDetector { /** If no motion is added for this amount of time, assume the motion has paused. */ private static final long FORCE_PAUSE_TIMEOUT = 300; + /** + * After {@link #makePauseHarderToTrigger()}, must + * move slowly for this long to trigger a pause. + */ + private static final long HARDER_TRIGGER_TIMEOUT = 400; + private final float mSpeedVerySlow; + private final float mSpeedSlow; private final float mSpeedSomewhatFast; private final float mSpeedFast; private final Alarm mForcePauseTimeout; + private final boolean mMakePauseHarderToTrigger; private Long mPreviousTime = null; private Float mPreviousPosition = null; @@ -52,19 +60,29 @@ public class MotionPauseDetector { private boolean mHasEverBeenPaused; /** @see #setDisallowPause(boolean) */ private boolean mDisallowPause; + // Time at which speed became < mSpeedSlow (only used if mMakePauseHarderToTrigger == true). + private long mSlowStartTime; public MotionPauseDetector(Context context) { + this(context, false); + } + + /** + * @param makePauseHarderToTrigger Used for gestures that require a more explicit pause. + */ + public MotionPauseDetector(Context context, boolean makePauseHarderToTrigger) { Resources res = context.getResources(); mSpeedVerySlow = res.getDimension(R.dimen.motion_pause_detector_speed_very_slow); + mSpeedSlow = res.getDimension(R.dimen.motion_pause_detector_speed_slow); mSpeedSomewhatFast = res.getDimension(R.dimen.motion_pause_detector_speed_somewhat_fast); mSpeedFast = res.getDimension(R.dimen.motion_pause_detector_speed_fast); mForcePauseTimeout = new Alarm(); mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */)); + mMakePauseHarderToTrigger = makePauseHarderToTrigger; } /** - * Get callbacks for when motion pauses and resumes, including an - * immediate callback with the current pause state. + * Get callbacks for when motion pauses and resumes. */ public void setOnMotionPauseListener(OnMotionPauseListener listener) { mOnMotionPauseListener = listener; @@ -88,13 +106,15 @@ public class MotionPauseDetector { if (mFirstPosition == null) { mFirstPosition = position; } - mForcePauseTimeout.setAlarm(FORCE_PAUSE_TIMEOUT); + mForcePauseTimeout.setAlarm(mMakePauseHarderToTrigger + ? HARDER_TRIGGER_TIMEOUT + : FORCE_PAUSE_TIMEOUT); if (mPreviousTime != null && mPreviousPosition != null) { long changeInTime = Math.max(1, time - mPreviousTime); float changeInPosition = position - mPreviousPosition; float velocity = changeInPosition / changeInTime; if (mPreviousVelocity != null) { - checkMotionPaused(velocity, mPreviousVelocity); + checkMotionPaused(velocity, mPreviousVelocity, time); } mPreviousVelocity = velocity; } @@ -102,7 +122,7 @@ public class MotionPauseDetector { mPreviousPosition = position; } - private void checkMotionPaused(float velocity, float prevVelocity) { + private void checkMotionPaused(float velocity, float prevVelocity, long time) { float speed = Math.abs(velocity); float previousSpeed = Math.abs(prevVelocity); boolean isPaused; @@ -122,6 +142,17 @@ public class MotionPauseDetector { boolean isRapidDeceleration = speed < previousSpeed * RAPID_DECELERATION_FACTOR; isPaused = isRapidDeceleration && speed < mSpeedSomewhatFast; } + if (mMakePauseHarderToTrigger) { + if (speed < mSpeedSlow) { + if (mSlowStartTime == 0) { + mSlowStartTime = time; + } + isPaused = time - mSlowStartTime >= HARDER_TRIGGER_TIMEOUT; + } else { + mSlowStartTime = 0; + isPaused = false; + } + } } } updatePaused(isPaused); @@ -149,6 +180,7 @@ public class MotionPauseDetector { mFirstPosition = null; setOnMotionPauseListener(null); mIsPaused = mHasEverBeenPaused = false; + mSlowStartTime = 0; mForcePauseTimeout.cancelAlarm(); } |