From 8b38295fb27b29fa1183fe71a78ec6f1d4282853 Mon Sep 17 00:00:00 2001 From: Holly Sun Date: Mon, 15 Apr 2024 17:20:25 -0700 Subject: [PATCH] [omni] Dynamically configure timeout for LPAA. Video: https://drive.google.com/file/d/1N7qOIolcSYM9n3z40FO9O6S_IdLJav9l/view?usp=sharing Bug: 335018496 Test: manual Flag: legacy CUSTOM_LPAA_THRESHOLDS disabled Change-Id: I5b0f7cc7815ecd85c51254ad34f2be521c44795c --- .../launcher3/taskbar/TaskbarView.java | 71 +++++++++++++++++-- .../taskbar/TaskbarViewCallbacks.java | 21 +++--- .../android/quickstep/DeviceConfigWrapper.kt | 7 ++ 3 files changed, 80 insertions(+), 19 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index df7a7ba84a..570221c872 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -24,6 +24,7 @@ import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER; import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR; import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning; import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.content.Context; import android.content.res.Resources; @@ -36,6 +37,7 @@ import android.view.InputDevice; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; @@ -63,6 +65,8 @@ import com.android.launcher3.util.LauncherBindableItemsContainer; import com.android.launcher3.util.Themes; import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.IconButtonView; +import com.android.quickstep.DeviceConfigWrapper; +import com.android.quickstep.util.AssistStateManager; import java.util.function.Predicate; @@ -71,8 +75,6 @@ import java.util.function.Predicate; */ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconParent, Insettable, DeviceProfile.OnDeviceProfileChangeListener { - private static final String TAG = "TaskbarView"; - private static final Rect sTmpRect = new Rect(); private final int[] mTempOutLocation = new int[2]; @@ -95,6 +97,9 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar // Only non-null when device supports having an All Apps button. private @Nullable IconButtonView mAllAppsButton; + private Runnable mAllAppsTouchRunnable; + private long mAllAppsButtonTouchDelayMs; + private boolean mAllAppsTouchTriggered; // Only non-null when device supports having an All Apps button. private @Nullable IconButtonView mTaskbarDivider; @@ -129,7 +134,6 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar mIsRtl = Utilities.isRtl(resources); mTransientTaskbarMinWidth = resources.getDimension(R.dimen.transient_taskbar_min_width); - onDeviceProfileChanged(mActivityContext.getDeviceProfile()); int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing); @@ -175,6 +179,9 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar // TODO: Disable touch events on QSB otherwise it can crash. mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false); + + // Default long press (touch) delay = 400ms + mAllAppsButtonTouchDelayMs = ViewConfiguration.getLongPressTimeout(); } @DrawableRes @@ -265,11 +272,20 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar mIconLongClickListener = mControllerCallbacks.getIconOnLongClickListener(); if (mAllAppsButton != null) { - mAllAppsButton.setOnClickListener(mControllerCallbacks.getAllAppsButtonClickListener()); - mAllAppsButton.setOnLongClickListener( - mControllerCallbacks.getAllAppsButtonLongClickListener()); + mAllAppsButton.setOnClickListener(this::onAllAppsButtonClick); + mAllAppsButton.setOnLongClickListener(this::onAllAppsButtonLongClick); + mAllAppsButton.setOnTouchListener(this::onAllAppsButtonTouch); mAllAppsButton.setHapticFeedbackEnabled( mControllerCallbacks.isAllAppsButtonHapticFeedbackEnabled()); + mAllAppsTouchRunnable = () -> { + mControllerCallbacks.triggerAllAppsButtonLongClick(); + mAllAppsTouchTriggered = true; + }; + AssistStateManager assistStateManager = AssistStateManager.INSTANCE.get(mContext); + if (DeviceConfigWrapper.get().getCustomLpaaThresholds() + && assistStateManager.getLPNHDurationMillis().isPresent()) { + mAllAppsButtonTouchDelayMs = assistStateManager.getLPNHDurationMillis().get(); + } } if (mTaskbarDivider != null && !mActivityContext.isThreeButtonNav()) { mTaskbarDivider.setOnLongClickListener( @@ -305,7 +321,6 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar } removeView(mQsb); - for (int i = 0; i < hotseatItemInfos.length; i++) { ItemInfo hotseatItemInfo = hotseatItemInfos[i]; if (hotseatItemInfo == null) { @@ -689,4 +704,46 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar } return mAllAppsButton; } + + private boolean onAllAppsButtonTouch(View view, MotionEvent ev) { + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + mAllAppsTouchTriggered = false; + MAIN_EXECUTOR.getHandler().postDelayed( + mAllAppsTouchRunnable, mAllAppsButtonTouchDelayMs); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + cancelAllAppsButtonTouch(); + } + return false; + } + + private void cancelAllAppsButtonTouch() { + MAIN_EXECUTOR.getHandler().removeCallbacks(mAllAppsTouchRunnable); + // ACTION_UP is first triggered, then click listener / long-click listener is triggered on + // the next frame, so we need to post twice and delay the reset. + if (mAllAppsButton != null) { + mAllAppsButton.post(() -> { + mAllAppsButton.post(() -> { + mAllAppsTouchTriggered = false; + }); + }); + } + } + + private void onAllAppsButtonClick(View view) { + if (!mAllAppsTouchTriggered) { + mControllerCallbacks.triggerAllAppsButtonClick(view); + } + } + + // Handle long click from Switch Access and Voice Access + private boolean onAllAppsButtonLongClick(View view) { + if (!MAIN_EXECUTOR.getHandler().hasCallbacks(mAllAppsTouchRunnable) + && !mAllAppsTouchTriggered) { + mControllerCallbacks.triggerAllAppsButtonLongClick(); + } + return true; + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java index c841cac3ca..3c646cb7fa 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java @@ -46,20 +46,17 @@ public class TaskbarViewCallbacks { return mActivity.getItemOnClickListener(); } - public View.OnClickListener getAllAppsButtonClickListener() { - return v -> { - InteractionJankMonitorWrapper.begin(v, Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS, - /* tag= */ "TASKBAR_BUTTON"); - mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP); - mControllers.taskbarAllAppsController.toggle(); - }; + /** Trigger All Apps button click action. */ + protected void triggerAllAppsButtonClick(View v) { + InteractionJankMonitorWrapper.begin(v, Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS, + /* tag= */ "TASKBAR_BUTTON"); + mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP); + mControllers.taskbarAllAppsController.toggle(); } - public View.OnLongClickListener getAllAppsButtonLongClickListener() { - return v -> { - mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_LONG_PRESS); - return true; - }; + /** Trigger All Apps button long click action. */ + protected void triggerAllAppsButtonLongClick() { + mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_LONG_PRESS); } public boolean isAllAppsButtonHapticFeedbackEnabled() { diff --git a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt index 0f844e1ec6..3549a1281d 100644 --- a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt +++ b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt @@ -37,6 +37,13 @@ class DeviceConfigWrapper private constructor(propReader: PropReader) { "Server side control to customize LPH timeout and touch slop" ) + val customLpaaThresholds = + propReader.get( + "CUSTOM_LPAA_THRESHOLDS", + false, + "Server side control to customize LPAA timeout and touch slop" + ) + val overrideLpnhLphThresholds = propReader.get( "OVERRIDE_LPNH_LPH_THRESHOLDS",