Merge "Add ScreenPinnedInputConsumer" into ub-launcher3-qt-dev

This commit is contained in:
TreeHugger Robot
2019-05-09 23:24:44 +00:00
committed by Android (Google) Code Review
6 changed files with 134 additions and 9 deletions
@@ -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;
}
@@ -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,
@@ -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;
@@ -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;
}
}
}
+1
View File
@@ -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>
@@ -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();
}