Merge "Revert "Revert "Add a way to stash/unstash transient taskbar.""" into tm-qpr-dev am: 8ed5ac05fd

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/20356225

Change-Id: I105e7ac5928083ef4d3793c76a0da357338c8b3b
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Jon Miranda
2022-11-03 06:30:53 +00:00
committed by Automerger Merge Worker
10 changed files with 365 additions and 46 deletions

View File

@@ -292,6 +292,7 @@
<dimen name="taskbar_app_window_threshold">150dp</dimen>
<dimen name="taskbar_home_overview_threshold">225dp</dimen>
<dimen name="taskbar_catch_up_threshold">300dp</dimen>
<dimen name="taskbar_nav_threshold">40dp</dimen>
<!-- Taskbar 3 button spacing -->
<dimen name="taskbar_button_space_inbetween">24dp</dimen>

View File

@@ -24,6 +24,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN;
import static com.android.launcher3.taskbar.TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW;
import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
@@ -75,6 +77,7 @@ import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.AutohideSuspendFlag;
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
import com.android.launcher3.testing.TestLogging;
@@ -297,13 +300,19 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
// Taskbar is on the logical bottom of the screen
boolean isVerticalBarLayout = TaskbarManager.isPhoneMode(deviceProfile) &&
deviceProfile.isLandscape;
int windowFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_SLIPPERY
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
if (DisplayController.isTransientTaskbar(this)) {
windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
}
WindowManager.LayoutParams windowLayoutParams = new WindowManager.LayoutParams(
isVerticalBarLayout ? mLastRequestedNonFullscreenHeight : MATCH_PARENT,
isVerticalBarLayout ? MATCH_PARENT : mLastRequestedNonFullscreenHeight,
type,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_SLIPPERY
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
windowFlags,
PixelFormat.TRANSLUCENT);
windowLayoutParams.setTitle(WINDOW_TITLE);
windowLayoutParams.packageName = getPackageName();
@@ -467,7 +476,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
@Override
public void onDragEnd() {
maybeSetTaskbarWindowNotFullscreen();
onDragEndOrViewRemoved();
}
@Override
@@ -571,25 +580,34 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
.updateValue(darkIntensity);
}
/**
* Called to update a {@link AutohideSuspendFlag} with a new value.
*/
public void setAutohideSuspendFlag(@AutohideSuspendFlag int flag, boolean newValue) {
mControllers.taskbarAutohideSuspendController.updateFlag(flag, newValue);
}
/**
* Updates the TaskbarContainer to MATCH_PARENT vs original Taskbar size.
*/
public void setTaskbarWindowFullscreen(boolean fullscreen) {
mControllers.taskbarAutohideSuspendController.updateFlag(
TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN, fullscreen);
setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_FULLSCREEN, fullscreen);
mIsFullscreen = fullscreen;
setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenHeight);
}
/**
* Reverts Taskbar window to its original size, if all floating views are closed and there is
* no system drag operation in progress.
* Called when drag ends or when a view is removed from the DragLayer.
*/
void maybeSetTaskbarWindowNotFullscreen() {
if (AbstractFloatingView.getAnyView(this, TYPE_ALL) == null
&& !mControllers.taskbarDragController.isSystemDragInProgress()) {
void onDragEndOrViewRemoved() {
boolean isDragInProgress = mControllers.taskbarDragController.isSystemDragInProgress();
if (!isDragInProgress && !AbstractFloatingView.hasOpenView(this, TYPE_ALL)) {
// Reverts Taskbar window to its original size
setTaskbarWindowFullscreen(false);
}
setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_DRAGGING, isDragInProgress);
}
public boolean isTaskbarWindowFullscreen() {
@@ -703,6 +721,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
Task task = (Task) tag;
ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key,
ActivityOptions.makeBasic());
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
} else if (tag instanceof FolderInfo) {
FolderIcon folderIcon = (FolderIcon) view;
Folder folder = folderIcon.getFolder();
@@ -762,6 +781,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
mControllers.uiController.onTaskbarIconLaunched(info);
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
} catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT)
.show();
@@ -771,6 +791,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
} else if (tag instanceof AppInfo) {
startItemInfoActivity((AppInfo) tag);
mControllers.uiController.onTaskbarIconLaunched((AppInfo) tag);
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
} else {
Log.e(TAG, "Unknown type clicked: " + tag);
}
@@ -805,6 +826,20 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
return mControllers.taskbarStashController.onLongPressToUnstashTaskbar();
}
/**
* Called when we want to unstash taskbar when user performs swipes up gesture.
*/
public void onSwipeToUnstashTaskbar() {
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
}
/**
* Called when a transient Autohide flag suspend status changes.
*/
public void onTransientAutohideSuspendFlagChanged(boolean isSuspended) {
mControllers.taskbarStashController.updateTaskbarTimeout(isSuspended);
}
/**
* Called when we detect a motion down or up/cancel in the nav region while stashed.
* @param animateForward Whether to animate towards the unstashed hint state or back to stashed.

View File

@@ -33,21 +33,28 @@ import java.util.StringJoiner;
public class TaskbarAutohideSuspendController implements
TaskbarControllers.LoggableTaskbarController {
// Taskbar window is fullscreen.
public static final int FLAG_AUTOHIDE_SUSPEND_FULLSCREEN = 1 << 0;
// User is dragging item.
public static final int FLAG_AUTOHIDE_SUSPEND_DRAGGING = 1 << 1;
// User has touched down but has not lifted finger.
public static final int FLAG_AUTOHIDE_SUSPEND_TOUCHING = 1 << 2;
@IntDef(flag = true, value = {
FLAG_AUTOHIDE_SUSPEND_FULLSCREEN,
FLAG_AUTOHIDE_SUSPEND_DRAGGING,
FLAG_AUTOHIDE_SUSPEND_TOUCHING,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AutohideSuspendFlag {}
private final TaskbarActivityContext mActivity;
private final SystemUiProxy mSystemUiProxy;
private @AutohideSuspendFlag int mAutohideSuspendFlags = 0;
public TaskbarAutohideSuspendController(TaskbarActivityContext activity) {
mActivity = activity;
mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity);
}
@@ -59,12 +66,27 @@ public class TaskbarAutohideSuspendController implements
* Adds or removes the given flag, then notifies system UI proxy whether to suspend auto-hide.
*/
public void updateFlag(@AutohideSuspendFlag int flag, boolean enabled) {
int flagsBefore = mAutohideSuspendFlags;
if (enabled) {
mAutohideSuspendFlags |= flag;
} else {
mAutohideSuspendFlags &= ~flag;
}
mSystemUiProxy.notifyTaskbarAutohideSuspend(mAutohideSuspendFlags != 0);
if (flagsBefore == mAutohideSuspendFlags) {
// Nothing has changed, no need to notify.
return;
}
boolean isSuspended = isSuspended();
mSystemUiProxy.notifyTaskbarAutohideSuspend(isSuspended);
mActivity.onTransientAutohideSuspendFlagChanged(isSuspended);
}
/**
* Returns true iff taskbar autohide is currently suspended.
*/
public boolean isSuspended() {
return mAutohideSuspendFlags != 0;
}
@Override
@@ -79,6 +101,7 @@ public class TaskbarAutohideSuspendController implements
appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_FULLSCREEN,
"FLAG_AUTOHIDE_SUSPEND_FULLSCREEN");
appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_DRAGGING, "FLAG_AUTOHIDE_SUSPEND_DRAGGING");
appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_TOUCHING, "FLAG_AUTOHIDE_SUSPEND_TOUCHING");
return str.toString();
}
}

View File

@@ -115,6 +115,14 @@ public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> {
return true;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mControllerCallbacks != null && ev.getAction() == MotionEvent.ACTION_OUTSIDE) {
mControllerCallbacks.onActionOutsideEvent();
}
return super.onTouchEvent(ev);
}
@Override
public void onViewRemoved(View child) {
super.onViewRemoved(child);

View File

@@ -23,6 +23,7 @@ import android.view.ViewTreeObserver;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.util.DimensionUtils;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.TouchController;
import com.android.quickstep.AnimatedFloat;
@@ -165,11 +166,25 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa
mControllers.taskbarInsetsController.updateInsetsTouchability(insetsInfo);
}
/**
* Called whenever TaskbarDragLayer receives an ACTION_OUTSIDE event.
*/
public void onActionOutsideEvent() {
if (!DisplayController.isTransientTaskbar(mActivity)) {
return;
}
if (mControllers.taskbarStashController.isStashed()) {
return;
}
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
}
/**
* Called when a child is removed from TaskbarDragLayer.
*/
public void onDragLayerViewRemoved() {
mActivity.maybeSetTaskbarWindowNotFullscreen();
mActivity.onDragEndOrViewRemoved();
}
/**

View File

@@ -39,11 +39,13 @@ import android.view.ViewConfiguration;
import androidx.annotation.NonNull;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.launcher3.Alarm;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.SystemUiProxy;
@@ -70,6 +72,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
public static final int FLAG_STASHED_IN_TASKBAR_ALL_APPS = 1 << 7; // All apps is visible.
public static final int FLAG_IN_SETUP = 1 << 8; // In the Setup Wizard
public static final int FLAG_STASHED_SMALL_SCREEN = 1 << 9; // phone screen gesture nav, stashed
public static final int FLAG_STASHED_IN_APP_AUTO = 1 << 10; // Autohide (transient taskbar).
// If any of these flags are enabled, isInApp should return true.
private static final int FLAGS_IN_APP = FLAG_IN_APP | FLAG_IN_SETUP;
@@ -78,7 +81,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
private static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_MANUAL
| FLAG_STASHED_IN_APP_PINNED | FLAG_STASHED_IN_APP_EMPTY | FLAG_STASHED_IN_APP_SETUP
| FLAG_STASHED_IN_APP_IME | FLAG_STASHED_IN_TASKBAR_ALL_APPS
| FLAG_STASHED_SMALL_SCREEN;
| FLAG_STASHED_SMALL_SCREEN | FLAG_STASHED_IN_APP_AUTO;
private static final int FLAGS_STASHED_IN_APP_IGNORING_IME =
FLAGS_STASHED_IN_APP & ~FLAG_STASHED_IN_APP_IME;
@@ -132,6 +135,9 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
*/
private static final boolean DEFAULT_STASHED_PREF = false;
// Auto stashes when user has not interacted with the Taskbar after X ms.
private static final long NO_TOUCH_TIMEOUT_TO_STASH_MS = 5000;
private final TaskbarActivityContext mActivity;
private final SharedPreferences mPrefs;
private final int mStashedHeight;
@@ -162,6 +168,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
private boolean mEnableManualStashingDuringTests = false;
private final Alarm mTimeoutAlarm = new Alarm();
// Evaluate whether the handle should be stashed
private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder(
flags -> {
@@ -210,13 +218,16 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
StashedHandleViewController.ALPHA_INDEX_STASHED);
mTaskbarStashedHandleHintScale = stashedHandleController.getStashedHandleHintScale();
boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity);
// We use supportsVisualStashing() here instead of supportsManualStashing() because we want
// it to work properly for tests that recreate taskbar. This check is here just to ensure
// that taskbar unstashes when going to 3 button mode (supportsVisualStashing() false).
boolean isManuallyStashedInApp = supportsVisualStashing()
&& mPrefs.getBoolean(SHARED_PREFS_STASHED_KEY, DEFAULT_STASHED_PREF);
&& mPrefs.getBoolean(SHARED_PREFS_STASHED_KEY, DEFAULT_STASHED_PREF)
&& !isTransientTaskbar;
boolean isInSetup = !mActivity.isUserSetupComplete() || setupUIVisible;
updateStateForFlag(FLAG_STASHED_IN_APP_MANUAL, isManuallyStashedInApp);
updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, isTransientTaskbar);
updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, isInSetup);
updateStateForFlag(FLAG_IN_SETUP, isInSetup);
updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, isPhoneMode()
@@ -243,7 +254,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
protected boolean supportsManualStashing() {
return supportsVisualStashing()
&& isInApp()
&& (!Utilities.IS_RUNNING_IN_TEST_HARNESS || mEnableManualStashingDuringTests);
&& (!Utilities.IS_RUNNING_IN_TEST_HARNESS || mEnableManualStashingDuringTests)
&& !DisplayController.isTransientTaskbar(mActivity);
}
/**
@@ -376,6 +388,20 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
return mStashedHeight;
}
/**
* Stash or unstashes the transient taskbar.
*/
public void updateAndAnimateTransientTaskbar(boolean stash) {
if (!DisplayController.isTransientTaskbar(mActivity)) {
return;
}
if (hasAnyFlag(FLAG_STASHED_IN_APP_AUTO) != stash) {
updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, stash);
applyState();
}
}
/**
* Should be called when long pressing the nav region when taskbar is present.
* @return Whether taskbar was stashed and now is unstashed.
@@ -549,11 +575,17 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
public void onAnimationStart(Animator animation) {
mIsStashed = isStashed;
onIsStashedChanged(mIsStashed);
cancelTimeoutIfExists();
}
@Override
public void onAnimationEnd(Animator animation) {
mAnimator = null;
if (!mIsStashed) {
tryStartTaskbarTimeout();
}
}
});
}
@@ -779,6 +811,54 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
mControllers.rotationButtonController.onTaskbarStateChange(visible, stashed);
}
/**
* Cancels a timeout if any exists.
*/
public void cancelTimeoutIfExists() {
if (mTimeoutAlarm.alarmPending()) {
mTimeoutAlarm.cancelAlarm();
}
}
/**
* Updates the status of the taskbar timeout.
* @param isAutohideSuspended If true, cancels any existing timeout
* If false, attempts to re/start the timeout
*/
public void updateTaskbarTimeout(boolean isAutohideSuspended) {
if (!DisplayController.isTransientTaskbar(mActivity)) {
return;
}
if (isAutohideSuspended) {
cancelTimeoutIfExists();
} else {
tryStartTaskbarTimeout();
}
}
/**
* Attempts to start timer to auto hide the taskbar based on time.
*/
public void tryStartTaskbarTimeout() {
if (!DisplayController.isTransientTaskbar(mActivity)) {
return;
}
if (mIsStashed) {
return;
}
cancelTimeoutIfExists();
mTimeoutAlarm.setOnAlarmListener(this::onTaskbarTimeout);
mTimeoutAlarm.setAlarm(NO_TOUCH_TIMEOUT_TO_STASH_MS);
}
private void onTaskbarTimeout(Alarm alarm) {
if (mControllers.taskbarAutohideSuspendController.isSuspended()) {
return;
}
updateAndAnimateTransientTaskbar(true);
}
@Override
public void dumpLogs(String prefix, PrintWriter pw) {
pw.println(prefix + "TaskbarStashController:");
@@ -794,17 +874,18 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
}
private static String getStateString(int flags) {
StringJoiner str = new StringJoiner("|");
appendFlag(str, flags, FLAGS_IN_APP, "FLAG_IN_APP");
appendFlag(str, flags, FLAG_STASHED_IN_APP_MANUAL, "FLAG_STASHED_IN_APP_MANUAL");
appendFlag(str, flags, FLAG_STASHED_IN_APP_PINNED, "FLAG_STASHED_IN_APP_PINNED");
appendFlag(str, flags, FLAG_STASHED_IN_APP_EMPTY, "FLAG_STASHED_IN_APP_EMPTY");
appendFlag(str, flags, FLAG_STASHED_IN_APP_SETUP, "FLAG_STASHED_IN_APP_SETUP");
appendFlag(str, flags, FLAG_STASHED_IN_APP_IME, "FLAG_STASHED_IN_APP_IME");
appendFlag(str, flags, FLAG_IN_STASHED_LAUNCHER_STATE, "FLAG_IN_STASHED_LAUNCHER_STATE");
appendFlag(str, flags, FLAG_STASHED_IN_TASKBAR_ALL_APPS, "FLAG_STASHED_IN_APP_ALL_APPS");
appendFlag(str, flags, FLAG_IN_SETUP, "FLAG_IN_SETUP");
return str.toString();
StringJoiner sj = new StringJoiner("|");
appendFlag(sj, flags, FLAGS_IN_APP, "FLAG_IN_APP");
appendFlag(sj, flags, FLAG_STASHED_IN_APP_MANUAL, "FLAG_STASHED_IN_APP_MANUAL");
appendFlag(sj, flags, FLAG_STASHED_IN_APP_PINNED, "FLAG_STASHED_IN_APP_PINNED");
appendFlag(sj, flags, FLAG_STASHED_IN_APP_EMPTY, "FLAG_STASHED_IN_APP_EMPTY");
appendFlag(sj, flags, FLAG_STASHED_IN_APP_SETUP, "FLAG_STASHED_IN_APP_SETUP");
appendFlag(sj, flags, FLAG_STASHED_IN_APP_IME, "FLAG_STASHED_IN_APP_IME");
appendFlag(sj, flags, FLAG_IN_STASHED_LAUNCHER_STATE, "FLAG_IN_STASHED_LAUNCHER_STATE");
appendFlag(sj, flags, FLAG_STASHED_IN_TASKBAR_ALL_APPS, "FLAG_STASHED_IN_TASKBAR_ALL_APPS");
appendFlag(sj, flags, FLAG_IN_SETUP, "FLAG_IN_SETUP");
appendFlag(sj, flags, FLAG_STASHED_IN_APP_AUTO, "FLAG_STASHED_IN_APP_AUTO");
return sj.toString();
}
private class StatePropertyHolder {

View File

@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.CallSuper;
@@ -104,6 +105,15 @@ public class TaskbarUIController {
return mControllers.taskbarStashController.isStashed();
}
/*
* @param ev MotionEvent in screen coordinates.
* @return Whether any Taskbar item could handle the given MotionEvent if given the chance.
*/
public boolean isEventOverAnyTaskbarItem(MotionEvent ev) {
return mControllers.taskbarViewController.isEventOverAnyItem(ev)
|| mControllers.navbarButtonsViewController.isEventOverAnyItem(ev);
}
@CallSuper
protected void dumpLogs(String prefix, PrintWriter pw) {
pw.println(String.format(

View File

@@ -344,13 +344,23 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
mControllerCallbacks.onInterceptTouchEvent(ev);
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!mTouchEnabled) {
return true;
}
if (mIconLayoutBounds.left <= event.getX() && event.getX() <= mIconLayoutBounds.right) {
// Don't allow long pressing between icons, or above/below them.
if (mIconLayoutBounds.left <= event.getX()
&& event.getX() <= mIconLayoutBounds.right
&& !DisplayController.isTransientTaskbar(mActivityContext)) {
// Don't allow long pressing between icons, or above/below them
// unless its transient taskbar.
mControllerCallbacks.clearTouchInProgress();
return true;
}
if (mControllerCallbacks.onTouchEvent(event)) {
@@ -367,6 +377,7 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
public void setTouchesEnabled(boolean touchEnabled) {
this.mTouchEnabled = touchEnabled;
mControllerCallbacks.clearTouchInProgress();
}
/**

View File

@@ -22,6 +22,8 @@ import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
import static com.android.launcher3.taskbar.TaskbarManager.isPhoneMode;
import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_NEGATIVE;
import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
import static com.android.quickstep.AnimatedFloat.VALUE;
import android.annotation.NonNull;
@@ -31,6 +33,7 @@ import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.core.graphics.ColorUtils;
import androidx.core.view.OneShotPreDrawListener;
@@ -47,6 +50,7 @@ import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.icons.ThemedIconDrawable;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.HorizontalInsettableView;
import com.android.launcher3.util.ItemInfoMatcher;
@@ -95,6 +99,9 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
private final TaskbarModelCallbacks mModelCallbacks;
// Captures swipe down action to close transient taskbar.
protected @Nullable SingleAxisSwipeDetector mSwipeDownDetector;
// Initialized in init.
private TaskbarControllers mControllers;
@@ -117,6 +124,31 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
mTaskbarBottomMargin = DisplayController.isTransientTaskbar(activity)
? activity.getResources().getDimensionPixelSize(R.dimen.transient_taskbar_margin)
: 0;
if (DisplayController.isTransientTaskbar(mActivity)) {
mSwipeDownDetector = new SingleAxisSwipeDetector(activity,
new SingleAxisSwipeDetector.Listener() {
private float mLastDisplacement;
@Override
public boolean onDrag(float displacement) {
mLastDisplacement = displacement;
return false;
}
@Override
public void onDragEnd(float velocity) {
if (mLastDisplacement > 0) {
mControllers.taskbarStashController
.updateAndAnimateTransientTaskbar(true);
}
}
@Override
public void onDragStart(boolean start, float startDisplacement) {}
}, VERTICAL);
mSwipeDownDetector.setDetectableScrollConditions(DIRECTION_NEGATIVE, false);
}
}
public void init(TaskbarControllers controllers) {
@@ -438,6 +470,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
private float mDownX, mDownY;
private boolean mCanceledStashHint;
private boolean mTouchInProgress;
public View.OnClickListener getIconOnClickListener() {
return mActivity.getItemOnClickListener();
}
@@ -458,38 +492,76 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
.updateAndAnimateIsManuallyStashedInApp(true);
}
/**
* Simply listens to all intercept touch events passed to TaskbarView.
*/
public void onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mTouchInProgress = true;
}
if (mTouchInProgress && mSwipeDownDetector != null) {
mSwipeDownDetector.onTouchEvent(ev);
}
if (ev.getAction() == MotionEvent.ACTION_UP
|| ev.getAction() == MotionEvent.ACTION_CANCEL) {
clearTouchInProgress();
}
}
/**
* Get the first chance to handle TaskbarView#onTouchEvent, and return whether we want to
* consume the touch so TaskbarView treats it as an ACTION_CANCEL.
*/
public boolean onTouchEvent(MotionEvent motionEvent) {
boolean shouldConsumeTouch = false;
boolean clearTouchInProgress = false;
final float x = motionEvent.getRawX();
final float y = motionEvent.getRawY();
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchInProgress = true;
mDownX = x;
mDownY = y;
mControllers.taskbarStashController.startStashHint(/* animateForward = */ true);
mCanceledStashHint = false;
break;
case MotionEvent.ACTION_MOVE:
if (!mCanceledStashHint
if (mTouchInProgress
&& !mCanceledStashHint
&& squaredHypot(mDownX - x, mDownY - y) > mSquaredTouchSlop) {
mControllers.taskbarStashController.startStashHint(
/* animateForward= */ false);
mCanceledStashHint = true;
return true;
shouldConsumeTouch = true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (!mCanceledStashHint) {
if (mTouchInProgress && !mCanceledStashHint) {
mControllers.taskbarStashController.startStashHint(
/* animateForward= */ false);
}
clearTouchInProgress = true;
break;
}
return false;
if (mTouchInProgress && mSwipeDownDetector != null) {
mSwipeDownDetector.onTouchEvent(motionEvent);
}
if (clearTouchInProgress) {
clearTouchInProgress();
}
return shouldConsumeTouch;
}
/**
* Ensures that we do not pass any more touch events to the SwipeDetector.
*/
public void clearTouchInProgress() {
mTouchInProgress = false;
}
}

View File

@@ -15,9 +15,14 @@
*/
package com.android.quickstep.inputconsumers;
import static android.view.MotionEvent.INVALID_POINTER_ID;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_TOUCHING;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PointF;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
@@ -25,6 +30,7 @@ import android.view.MotionEvent;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.InputConsumer;
import com.android.systemui.shared.system.InputMonitorCompat;
@@ -37,20 +43,32 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer {
private final GestureDetector mLongPressDetector;
private final float mSquaredTouchSlop;
private float mDownX, mDownY;
private float mLongPressDownX, mLongPressDownY;
private boolean mCanceledUnstashHint;
private final float mUnstashArea;
private final float mScreenWidth;
private final int mTaskbarThreshold;
private boolean mHasPassedTaskbarThreshold;
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
private int mActivePointerId = INVALID_POINTER_ID;
private final boolean mIsTransientTaskbar;
public TaskbarStashInputConsumer(Context context, InputConsumer delegate,
InputMonitorCompat inputMonitor, TaskbarActivityContext taskbarActivityContext) {
super(delegate, inputMonitor);
mTaskbarActivityContext = taskbarActivityContext;
mSquaredTouchSlop = Utilities.squaredTouchSlop(context);
mScreenWidth = taskbarActivityContext.getDeviceProfile().widthPx;
mUnstashArea = context.getResources()
.getDimensionPixelSize(R.dimen.taskbar_unstash_input_area);
Resources res = context.getResources();
mUnstashArea = res.getDimensionPixelSize(R.dimen.taskbar_unstash_input_area);
mTaskbarThreshold = res.getDimensionPixelSize(R.dimen.taskbar_nav_threshold);
mIsTransientTaskbar = DisplayController.isTransientTaskbar(context);
mLongPressDetector = new GestureDetector(context, new SimpleOnGestureListener() {
@Override
@@ -76,28 +94,71 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer {
final float y = ev.getRawY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = ev.getPointerId(0);
mDownPos.set(ev.getX(), ev.getY());
mLastPos.set(mDownPos);
mHasPassedTaskbarThreshold = false;
mTaskbarActivityContext.setAutohideSuspendFlag(
FLAG_AUTOHIDE_SUSPEND_TOUCHING, true);
if (isInArea(x)) {
mDownX = x;
mDownY = y;
mTaskbarActivityContext.startTaskbarUnstashHint(
/* animateForward = */ true);
mCanceledUnstashHint = false;
if (!mIsTransientTaskbar) {
mLongPressDownX = x;
mLongPressDownY = y;
mTaskbarActivityContext.startTaskbarUnstashHint(
/* animateForward = */ true);
mCanceledUnstashHint = false;
}
}
break;
case MotionEvent.ACTION_POINTER_UP:
int ptrIdx = ev.getActionIndex();
int ptrId = ev.getPointerId(ptrIdx);
if (ptrId == mActivePointerId) {
final int newPointerIdx = ptrIdx == 0 ? 1 : 0;
mDownPos.set(
ev.getX(newPointerIdx) - (mLastPos.x - mDownPos.x),
ev.getY(newPointerIdx) - (mLastPos.y - mDownPos.y));
mLastPos.set(ev.getX(newPointerIdx), ev.getY(newPointerIdx));
mActivePointerId = ev.getPointerId(newPointerIdx);
}
break;
case MotionEvent.ACTION_MOVE:
if (!mCanceledUnstashHint
&& squaredHypot(mDownX - x, mDownY - y) > mSquaredTouchSlop) {
if (!mIsTransientTaskbar
&& !mCanceledUnstashHint
&& squaredHypot(mLongPressDownX - x, mLongPressDownY - y)
> mSquaredTouchSlop) {
mTaskbarActivityContext.startTaskbarUnstashHint(
/* animateForward = */ false);
mCanceledUnstashHint = true;
}
int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == INVALID_POINTER_ID) {
break;
}
mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
float displacementY = mLastPos.y - mDownPos.y;
float verticalDist = Math.abs(displacementY);
boolean passedTaskbarThreshold = verticalDist >= mTaskbarThreshold;
if (!mHasPassedTaskbarThreshold
&& passedTaskbarThreshold
&& mIsTransientTaskbar) {
mHasPassedTaskbarThreshold = true;
mTaskbarActivityContext.onSwipeToUnstashTaskbar();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (!mCanceledUnstashHint) {
if (!mIsTransientTaskbar && !mCanceledUnstashHint) {
mTaskbarActivityContext.startTaskbarUnstashHint(
/* animateForward = */ false);
}
mTaskbarActivityContext.setAutohideSuspendFlag(
FLAG_AUTOHIDE_SUSPEND_TOUCHING, false);
mHasPassedTaskbarThreshold = false;
break;
}
}
@@ -111,7 +172,9 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer {
}
private void onLongPressDetected(MotionEvent motionEvent) {
if (mTaskbarActivityContext != null && isInArea(motionEvent.getRawX())) {
if (mTaskbarActivityContext != null
&& isInArea(motionEvent.getRawX())
&& !mIsTransientTaskbar) {
boolean taskBarPressed = mTaskbarActivityContext.onLongPressToUnstashTaskbar();
if (taskBarPressed) {
setActive(motionEvent);