Merge "Handle long press directly if recents transition is deferred" into main
diff --git a/quickstep/res/layout/taskbar_divider_popup_menu.xml b/quickstep/res/layout/taskbar_divider_popup_menu.xml
index 4348a47..6fbb586 100644
--- a/quickstep/res/layout/taskbar_divider_popup_menu.xml
+++ b/quickstep/res/layout/taskbar_divider_popup_menu.xml
@@ -38,6 +38,7 @@
android:theme="@style/PopupItem">
<View
+ android:id="@+id/taskbar_pinning_visibility_icon"
android:layout_margin="6dp"
android:layout_width="20dp"
android:layout_height="20dp"
@@ -45,13 +46,17 @@
android:backgroundTint="?android:attr/textColorPrimary" />
<Switch
- style="@style/BaseIcon"
+ style="@style/Switch.SettingsLib"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:id="@+id/taskbar_pinning_switch"
android:background="@null"
android:clickable="false"
android:gravity="start|center_vertical"
android:textAlignment="viewStart"
android:paddingStart="12dp"
+ android:layout_weight="1"
+ android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
android:singleLine="true"
android:ellipsize="end"
android:textSize="14sp"
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index aaa699b..22f98fa 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -386,6 +386,7 @@
<!--- Taskbar Pinning -->
<dimen name="taskbar_pinning_popup_menu_width">300dp</dimen>
+ <dimen name="taskbar_pinning_popup_menu_vertical_margin">16dp</dimen>
<!-- Recents overview -->
<dimen name="recents_filter_icon_size">30dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
index d13b53f..3f9b66a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
@@ -15,22 +15,29 @@
*/
package com.android.launcher3.taskbar
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
+import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Rect
import android.graphics.drawable.GradientDrawable
import android.util.AttributeSet
+import android.util.Property
import android.view.Gravity
import android.view.MotionEvent
import android.view.View
import android.widget.LinearLayout
import android.widget.Switch
import androidx.core.view.postDelayed
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.launcher3.R
import com.android.launcher3.popup.ArrowPopup
import com.android.launcher3.popup.RoundedArrowDrawable
import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.Themes
+import com.android.launcher3.views.ActivityContext
/** Popup view with arrow for taskbar pinning */
class TaskbarDividerPopupView<T : TaskbarActivityContext>
@@ -42,7 +49,8 @@
) : ArrowPopup<T>(context, attrs, defStyleAttr) {
companion object {
private const val TAG = "TaskbarDividerPopupView"
- private const val DIVIDER_POPUP_CLOSING_DELAY = 500L
+ private const val DIVIDER_POPUP_CLOSING_DELAY = 333L
+ private const val DIVIDER_POPUP_CLOSING_ANIMATION_DURATION = 83L
@JvmStatic
fun createAndPopulate(
@@ -63,7 +71,7 @@
private lateinit var dividerView: View
private val menuWidth =
- context.resources.getDimensionPixelSize(R.dimen.taskbar_pinning_popup_menu_width)
+ resources.getDimensionPixelSize(R.dimen.taskbar_pinning_popup_menu_width)
private val popupCornerRadius = Themes.getDialogCornerRadius(context)
private val arrowWidth = resources.getDimension(R.dimen.popup_arrow_width)
private val arrowHeight = resources.getDimension(R.dimen.popup_arrow_height)
@@ -71,6 +79,8 @@
private var alwaysShowTaskbarOn = !DisplayController.isTransientTaskbar(context)
private var didPreferenceChange = false
+ private var verticalOffsetForPopupView =
+ resources.getDimensionPixelSize(R.dimen.taskbar_pinning_popup_menu_vertical_margin)
/** Callback invoked when the pinning popup view is closing. */
var onCloseCallback: (preferenceChanged: Boolean) -> Unit = {}
@@ -94,11 +104,22 @@
super.onFinishInflate()
val taskbarSwitchOption = requireViewById<LinearLayout>(R.id.taskbar_switch_option)
val alwaysShowTaskbarSwitch = requireViewById<Switch>(R.id.taskbar_pinning_switch)
+ val taskbarVisibilityIcon = requireViewById<View>(R.id.taskbar_pinning_visibility_icon)
alwaysShowTaskbarSwitch.isChecked = alwaysShowTaskbarOn
- taskbarSwitchOption.setOnClickListener {
- alwaysShowTaskbarSwitch.isClickable = true
- alwaysShowTaskbarSwitch.isChecked = !alwaysShowTaskbarOn
- onClickAlwaysShowTaskbarSwitchOption()
+ if (ActivityContext.lookupContext<TaskbarActivityContext>(context).isGestureNav) {
+ taskbarSwitchOption.setOnClickListener {
+ alwaysShowTaskbarSwitch.isClickable = true
+ alwaysShowTaskbarSwitch.isChecked = !alwaysShowTaskbarOn
+ onClickAlwaysShowTaskbarSwitchOption()
+ }
+ } else {
+ alwaysShowTaskbarSwitch.isEnabled = false
+ }
+
+ if (!alwaysShowTaskbarSwitch.isEnabled) {
+ taskbarVisibilityIcon.background.setTint(
+ resources.getColor(android.R.color.system_neutral2_500, context.theme)
+ )
}
}
@@ -171,10 +192,71 @@
}
}
- override fun closeComplete() {
+ override fun getExtraVerticalOffset(): Int {
+ return (mActivityContext.deviceProfile.taskbarHeight -
+ mActivityContext.deviceProfile.taskbarIconSize) / 2 + verticalOffsetForPopupView
+ }
+
+ override fun animateClose() {
+ if (!mIsOpen) {
+ return
+ }
+ if (mOpenCloseAnimator != null) {
+ mOpenCloseAnimator.cancel()
+ }
+ mIsOpen = false
+
+ mOpenCloseAnimator = getCloseAnimator()
+
+ mOpenCloseAnimator.addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ mOpenCloseAnimator = null
+ if (mDeferContainerRemoval) {
+ setVisibility(INVISIBLE)
+ } else {
+ closeComplete()
+ }
+ }
+ }
+ )
onCloseCallback(didPreferenceChange)
onCloseCallback = {}
- super.closeComplete()
+ mOpenCloseAnimator.start()
+ }
+
+ private fun getCloseAnimator(): AnimatorSet {
+ val alphaValues = floatArrayOf(1f, 0f)
+ val translateYValue =
+ if (!alwaysShowTaskbarOn) verticalOffsetForPopupView else -verticalOffsetForPopupView
+ val alpha = getAnimatorOfFloat(this, ALPHA, *alphaValues)
+ val arrowAlpha = getAnimatorOfFloat(mArrow, ALPHA, *alphaValues)
+ val translateY =
+ ObjectAnimator.ofFloat(
+ this,
+ TRANSLATION_Y,
+ *floatArrayOf(this.translationY, this.translationY + translateYValue)
+ )
+ val arrowTranslateY =
+ ObjectAnimator.ofFloat(
+ mArrow,
+ TRANSLATION_Y,
+ *floatArrayOf(mArrow.translationY, mArrow.translationY + translateYValue)
+ )
+ val animatorSet = AnimatorSet()
+ animatorSet.playTogether(alpha, arrowAlpha, translateY, arrowTranslateY)
+ return animatorSet
+ }
+
+ private fun getAnimatorOfFloat(
+ view: View,
+ property: Property<View, Float>,
+ vararg values: Float
+ ): Animator {
+ val animator: Animator = ObjectAnimator.ofFloat(view, property, *values)
+ animator.setDuration(DIVIDER_POPUP_CLOSING_ANIMATION_DURATION)
+ animator.interpolator = EMPHASIZED_ACCELERATE
+ return animator
}
private fun onClickAlwaysShowTaskbarSwitchOption() {
@@ -182,7 +264,7 @@
// Allow switch animation to finish and then close the popup.
postDelayed(DIVIDER_POPUP_CLOSING_DELAY) {
if (isOpen) {
- close(false)
+ close(true)
}
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
index d1bed3e..cbfa024 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
@@ -82,9 +82,12 @@
taskbarViewController.taskbarIconTranslationXForPinning.animateToValue(animateToValue)
)
+ controllers.taskbarOverlayController.hideWindow()
+
animatorSet.doOnEnd { recreateTaskbarAndUpdatePinningValue() }
animatorSet.duration = PINNING_ANIMATION_DURATION
updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(true)
+ taskbarViewController.animateAwayNotificationDotsDuringTaskbarPinningAnimation()
animatorSet.start()
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index fd66b45..78d5bd3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -52,6 +52,7 @@
import androidx.core.view.OneShotPreDrawListener;
import com.android.app.animation.Interpolators;
+import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
@@ -338,6 +339,17 @@
}
}
+ /**
+ * Animate away taskbar icon notification dots during the taskbar pinning animation.
+ */
+ public void animateAwayNotificationDotsDuringTaskbarPinningAnimation() {
+ for (View iconView : mTaskbarView.getIconViews()) {
+ if (iconView instanceof BubbleTextView && ((BubbleTextView) iconView).hasDot()) {
+ ((BubbleTextView) iconView).animateDotScale(0);
+ }
+ }
+ }
+
private void updateTaskbarIconTranslationXForPinning() {
View[] iconViews = mTaskbarView.getIconViews();
float scale = mTaskbarIconTranslationXForPinning.value;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
index 6279f63..28d4bf8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
@@ -57,6 +57,7 @@
public static final String NAMESPACE_LAUNCHER = "launcher";
private static final List<DebugFlag> sDebugFlags = new ArrayList<>();
+ private static final List<IntFlag> sIntFlags = new ArrayList<>();
private static SharedPreferences sSharedPreferences;
static final BooleanFlag TEAMFOOD_FLAG = getReleaseFlag(
@@ -132,7 +133,14 @@
public static IntFlag getIntFlag(
int bugId, String key, int defaultValueInCode, String description) {
INSTANCE.mKeySet.add(key);
- return new IntFlag(DeviceConfig.getInt(NAMESPACE_LAUNCHER, key, defaultValueInCode));
+ int defaultValue = DeviceConfig.getInt(NAMESPACE_LAUNCHER, key, defaultValueInCode);
+ if (IS_DEBUG_DEVICE) {
+ IntDeviceFlag flag = new IntDeviceFlag(key, defaultValue, defaultValueInCode);
+ sIntFlags.add(flag);
+ return flag;
+ } else {
+ return new IntFlag(defaultValue);
+ }
}
static List<DebugFlag> getDebugFlags() {
@@ -163,13 +171,20 @@
return;
}
pw.println("DeviceFlags:");
+ pw.println(" BooleanFlags:");
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
if (flag instanceof DeviceFlag) {
- pw.println(" " + flag);
+ pw.println(" " + flag);
}
}
}
+ pw.println(" IntFlags:");
+ synchronized (sIntFlags) {
+ for (IntFlag flag : sIntFlags) {
+ pw.println(" " + flag);
+ }
+ }
pw.println("DebugFlags:");
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/IntDeviceFlag.java b/quickstep/src/com/android/launcher3/uioverrides/flags/IntDeviceFlag.java
new file mode 100644
index 0000000..4f3b0ae
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/IntDeviceFlag.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 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.launcher3.uioverrides.flags;
+
+import com.android.launcher3.config.FeatureFlags.IntFlag;
+
+public class IntDeviceFlag extends IntFlag {
+ public final String key;
+ private final int mDefaultValueInCode;
+
+ public IntDeviceFlag(String key, int currentValue, int defaultValueInCode) {
+ super(currentValue);
+ this.key = key;
+ mDefaultValueInCode = defaultValueInCode;
+ }
+
+ @Override
+ public String toString() {
+ return key + ": mCurrentValue=" + get() + ", defaultValueInCode=" + mDefaultValueInCode;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 8d26fd4..db5ad82 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -23,9 +23,9 @@
import static com.android.launcher3.util.DisplayController.CHANGE_ALL;
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.NavigationMode.NO_BUTTON;
import static com.android.launcher3.util.NavigationMode.THREE_BUTTONS;
-import static com.android.launcher3.util.NavigationMode.TWO_BUTTONS;
import static com.android.launcher3.util.SettingsCache.ONE_HANDED_ENABLED;
import static com.android.launcher3.util.SettingsCache.ONE_HANDED_SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
@@ -55,8 +55,11 @@
import android.os.RemoteException;
import android.os.SystemProperties;
import android.provider.Settings;
+import android.util.Log;
+import android.view.ISystemGestureExclusionListener;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+import android.view.WindowManagerGlobal;
import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
@@ -74,7 +77,6 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
-import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -86,6 +88,8 @@
*/
public class RecentsAnimationDeviceState implements DisplayInfoChangeListener {
+ private static final String TAG = "RecentsAnimationDeviceState";
+
static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
// TODO: Move to quickstep contract
@@ -95,6 +99,23 @@
private final Context mContext;
private final DisplayController mDisplayController;
private final int mDisplayId;
+
+ private final ISystemGestureExclusionListener mGestureExclusionListener =
+ new ISystemGestureExclusionListener.Stub() {
+ @BinderThread
+ @Override
+ public void onSystemGestureExclusionChanged(int displayId,
+ Region systemGestureExclusionRegion, Region unrestrictedOrNull) {
+ if (displayId != mDisplayId) {
+ return;
+ }
+ // Assignments are atomic, it should be safe on binder thread. Also we don't
+ // think systemGestureExclusionRegion can be null but just in case, don't let
+ // mExclusionRegion be null.
+ mExclusionRegion = systemGestureExclusionRegion != null
+ ? systemGestureExclusionRegion : new Region();
+ }
+ };
private final RotationTouchHelper mRotationTouchHelper;
private final TaskStackChangeListener mPipListener;
// Cache for better performance since it doesn't change at runtime.
@@ -118,7 +139,7 @@
private int mGestureBlockingTaskId = -1;
private @NonNull Region mExclusionRegion = new Region();
- private SystemGestureExclusionListenerCompat mExclusionListener;
+ private boolean mExclusionListenerRegistered;
public RecentsAnimationDeviceState(Context context) {
this(context, false);
@@ -142,19 +163,7 @@
}
// Register for exclusion updates
- mExclusionListener = new SystemGestureExclusionListenerCompat(mDisplayId) {
- @Override
- @BinderThread
- public void onExclusionChanged(Region region) {
- if (region == null) {
- // Don't think this is possible but just in case, don't let it be null.
- region = new Region();
- }
- // Assignments are atomic, it should be safe on binder thread
- mExclusionRegion = region;
- }
- };
- runOnDestroy(mExclusionListener::unregister);
+ runOnDestroy(() -> unregisterExclusionListener());
// Register for display changes changes
mDisplayController.addChangeListener(this);
@@ -247,13 +256,54 @@
mNavBarPosition = new NavBarPosition(mMode, info);
if (mMode == NO_BUTTON) {
- mExclusionListener.register();
+ registerExclusionListener();
} else {
- mExclusionListener.unregister();
+ unregisterExclusionListener();
}
}
}
+ /**
+ * Registers {@link mGestureExclusionListener} for getting exclusion rect changes. Note that we
+ * make binder call on {@link UI_HELPER_EXECUTOR} to avoid jank.
+ */
+ public void registerExclusionListener() {
+ UI_HELPER_EXECUTOR.execute(() -> {
+ if (mExclusionListenerRegistered) {
+ return;
+ }
+ try {
+ WindowManagerGlobal.getWindowManagerService()
+ .registerSystemGestureExclusionListener(
+ mGestureExclusionListener, mDisplayId);
+ mExclusionListenerRegistered = true;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to register window manager callbacks", e);
+ }
+ });
+ }
+
+ /**
+ * Unregisters {@link mGestureExclusionListener} if previously registered. We make binder call
+ * on same {@link UI_HELPER_EXECUTOR} as in {@link #registerExclusionListener()} so that
+ * read/write {@link mExclusionListenerRegistered} field is thread safe.
+ */
+ public void unregisterExclusionListener() {
+ UI_HELPER_EXECUTOR.execute(() -> {
+ if (!mExclusionListenerRegistered) {
+ return;
+ }
+ try {
+ WindowManagerGlobal.getWindowManagerService()
+ .unregisterSystemGestureExclusionListener(
+ mGestureExclusionListener, mDisplayId);
+ mExclusionListenerRegistered = false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to unregister window manager callbacks", e);
+ }
+ });
+ }
+
public void onOneHandedModeChanged(int newGesturalHeight) {
mRotationTouchHelper.setGesturalHeight(newGesturalHeight);
}
@@ -280,13 +330,6 @@
}
/**
- * @return whether the current nav mode is 2-button-based.
- */
- public boolean isTwoButtonNavMode() {
- return mMode == TWO_BUTTONS;
- }
-
- /**
* @return whether the current nav mode is button-based.
*/
public boolean isButtonNavMode() {
@@ -391,13 +434,6 @@
}
/**
- * @return whether notification panel is expanded
- */
- public boolean isNotificationPanelExpanded() {
- return (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) != 0;
- }
-
- /**
* @return whether the global actions dialog is showing
*/
public boolean isSystemUiDialogShowing() {
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 5147538..00d8008 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -17,7 +17,6 @@
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
-import static com.android.launcher3.testing.shared.TestProtocol.SPLIT_LEAK;
import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -99,6 +98,7 @@
import com.android.wm.shell.transition.IShellTransitions;
import com.android.wm.shell.util.GroupedRecentTaskInfo;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
@@ -272,7 +272,6 @@
*/
@MainThread
public void clearProxy() {
- testLogD(SPLIT_LEAK, "systemUiProxy clearingProxy");
setProxy(null, null, null, null, null, null, null, null, null, null, null, null, null);
}
@@ -401,6 +400,17 @@
}
@Override
+ public void animateNavBarLongPress(boolean isTouchDown, long durationMs) {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.animateNavBarLongPress(isTouchDown, durationMs);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call animateNavBarLongPress", e);
+ }
+ }
+ }
+
+ @Override
public void notifyAccessibilityButtonClicked(int displayId) {
if (mSystemUiProxy != null) {
try {
@@ -1252,19 +1262,21 @@
}
public ArrayList<GroupedRecentTaskInfo> getRecentTasks(int numTasks, int userId) {
- if (mRecentTasks != null) {
- try {
- final GroupedRecentTaskInfo[] rawTasks = mRecentTasks.getRecentTasks(numTasks,
- RECENT_IGNORE_UNAVAILABLE, userId);
- if (rawTasks == null) {
- return new ArrayList<>();
- }
- return new ArrayList<>(Arrays.asList(rawTasks));
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call getRecentTasks", e);
- }
+ if (mRecentTasks == null) {
+ Log.w(TAG, "getRecentTasks() failed due to null mRecentTasks");
+ return new ArrayList<>();
}
- return new ArrayList<>();
+ try {
+ final GroupedRecentTaskInfo[] rawTasks = mRecentTasks.getRecentTasks(numTasks,
+ RECENT_IGNORE_UNAVAILABLE, userId);
+ if (rawTasks == null) {
+ return new ArrayList<>();
+ }
+ return new ArrayList<>(Arrays.asList(rawTasks));
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call getRecentTasks", e);
+ return new ArrayList<>();
+ }
}
/**
@@ -1408,7 +1420,7 @@
public boolean startRecentsActivity(Intent intent, ActivityOptions options,
RecentsAnimationListener listener) {
if (mRecentTasks == null) {
- ActiveGestureLog.INSTANCE.trackEvent(RECENT_TASKS_MISSING);
+ ActiveGestureLog.INSTANCE.addLog("Null mRecentTasks", RECENT_TASKS_MISSING);
return false;
}
final IRecentsAnimationRunner runner = new IRecentsAnimationRunner.Stub() {
@@ -1466,4 +1478,35 @@
return false;
}
}
+
+ public void dump(PrintWriter pw) {
+ pw.println(TAG + ":");
+
+ pw.println("\tmSystemUiProxy=" + mSystemUiProxy);
+ pw.println("\tmPip=" + mPip);
+ pw.println("\tmPipAnimationListener=" + mPipAnimationListener);
+ pw.println("\tmBubbles=" + mBubbles);
+ pw.println("\tmBubblesListener=" + mBubblesListener);
+ pw.println("\tmSplitScreen=" + mSplitScreen);
+ pw.println("\tmSplitScreenListener=" + mSplitScreenListener);
+ pw.println("\tmSplitSelectListener=" + mSplitSelectListener);
+ pw.println("\tmOneHanded=" + mOneHanded);
+ pw.println("\tmShellTransitions=" + mShellTransitions);
+ pw.println("\tmHomeTransitionListener=" + mHomeTransitionListener);
+ pw.println("\tmStartingWindow=" + mStartingWindow);
+ pw.println("\tmStartingWindowListener=" + mStartingWindowListener);
+ pw.println("\tmSysuiUnlockAnimationController=" + mSysuiUnlockAnimationController);
+ pw.println("\tmLauncherActivityClass=" + mLauncherActivityClass);
+ pw.println("\tmLauncherUnlockAnimationController=" + mLauncherUnlockAnimationController);
+ pw.println("\tmRecentTasks=" + mRecentTasks);
+ pw.println("\tmRecentTasksListener=" + mRecentTasksListener);
+ pw.println("\tmBackAnimation=" + mBackAnimation);
+ pw.println("\tmBackToLauncherCallback=" + mBackToLauncherCallback);
+ pw.println("\tmBackToLauncherRunner=" + mBackToLauncherRunner);
+ pw.println("\tmDesktopMode=" + mDesktopMode);
+ pw.println("\tmDesktopTaskListener=" + mDesktopTaskListener);
+ pw.println("\tmUnfoldAnimation=" + mUnfoldAnimation);
+ pw.println("\tmUnfoldAnimationListener=" + mUnfoldAnimationListener);
+ pw.println("\tmDragAndDrop=" + mDragAndDrop);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 662a895..3d8191d 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -693,15 +693,17 @@
launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE);
launcherAnim.setDuration(RECENTS_LAUNCH_DURATION);
- windowAnimEndListener = new AnimatorListenerAdapter() {
+ windowAnimEndListener = new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
recentsView.onTaskLaunchedInLiveTileMode();
}
// Make sure recents gets fixed up by resetting task alphas and scales, etc.
+ // This should only be run onAnimationSuccess, otherwise finishRecentsAnimation will
+ // interfere with a rapid swipe up to home in the live tile + running task case.
@Override
- public void onAnimationEnd(Animator animation) {
+ public void onAnimationSuccess(Animator animation) {
recentsView.finishRecentsAnimation(false /* toRecents */, () -> {
recentsView.post(() -> {
stateManager.moveToRestState();
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 7399c31..b4fe5e4 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -1374,6 +1374,7 @@
mTaskbarManager.dumpLogs("", pw);
pw.println("AssistStateManager:");
AssistStateManager.INSTANCE.get(this).dump(" ", pw);
+ SystemUiProxy.INSTANCE.get(this).dump(pw);
}
private AbsSwipeUpHandler createLauncherSwipeHandler(
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index efa84d3..d38376c 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -38,7 +38,6 @@
private final NavHandleLongPressHandler mNavHandleLongPressHandler;
private final float mNavHandleWidth;
private final float mScreenWidth;
- private final ViewConfiguration mViewConfiguration;
private final Runnable mTriggerLongPress = this::triggerLongPress;
private final float mTouchSlopSquared;
@@ -49,7 +48,6 @@
public NavHandleLongPressInputConsumer(Context context, InputConsumer delegate,
InputMonitorCompat inputMonitor, RecentsAnimationDeviceState deviceState) {
super(delegate, inputMonitor);
- mViewConfiguration = ViewConfiguration.get(context);
mNavHandleWidth = context.getResources().getDimensionPixelSize(
R.dimen.navigation_home_handle_width);
mScreenWidth = DisplayController.INSTANCE.get(context).getInfo().currentSize.x;
@@ -69,6 +67,18 @@
@Override
public void onMotionEvent(MotionEvent ev) {
+ if (mDelegate.allowInterceptByParent()) {
+ handleMotionEvent(ev);
+ } else if (MAIN_EXECUTOR.getHandler().hasCallbacks(mTriggerLongPress)) {
+ cancelLongPress();
+ }
+
+ if (mState != STATE_ACTIVE) {
+ mDelegate.onMotionEvent(ev);
+ }
+ }
+
+ private void handleMotionEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN -> {
if (mCurrentDownEvent != null) {
@@ -103,10 +113,6 @@
MAIN_EXECUTOR.getHandler().removeCallbacks(mTriggerLongPress);
MAIN_EXECUTOR.getHandler().post(mTriggerLongPress);
}
-
- if (mState != STATE_ACTIVE) {
- mDelegate.onMotionEvent(ev);
- }
}
private void triggerLongPress() {
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 1f6dae6..fce188f 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -15,6 +15,9 @@
*/
package com.android.quickstep.interaction;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+
import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.Utilities.mapBoundToRange;
@@ -47,6 +50,8 @@
import android.util.Log;
import android.view.View;
import android.view.View.AccessibilityDelegate;
+import android.view.Window;
+import android.view.WindowInsetsController;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.widget.ImageView;
@@ -122,6 +127,17 @@
Resources resources = getResources();
int mode = resources.getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
boolean isDarkTheme = mode == Configuration.UI_MODE_NIGHT_YES;
+
+ int systemBarsMask = APPEARANCE_LIGHT_STATUS_BARS | APPEARANCE_LIGHT_NAVIGATION_BARS;
+ int systemBarsAppearance = isDarkTheme ? 0 : systemBarsMask;
+ Window window = getWindow();
+ WindowInsetsController insetsController = window == null
+ ? null
+ : window.getInsetsController();
+ if (insetsController != null) {
+ insetsController.setSystemBarsAppearance(systemBarsAppearance, systemBarsMask);
+ }
+
Intent intent = getIntent();
int accentColor = intent.getIntExtra(
isDarkTheme ? EXTRA_ACCENT_COLOR_DARK_MODE : EXTRA_ACCENT_COLOR_LIGHT_MODE,
@@ -300,7 +316,9 @@
if (mBackgroundAnimatorListener != null) {
mAnimatedBackground.removeAnimatorListener(mBackgroundAnimatorListener);
}
- dispatchLauncherAnimStartEnd();
+ if (!isChangingConfigurations()) {
+ dispatchLauncherAnimStartEnd();
+ }
}
private AnimatedFloat createSwipeUpProxy(GestureState state) {
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 16235e0..12568ea 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -162,6 +162,7 @@
@Before
public void setUp() {
mLauncher.onTestStart();
+ AbstractLauncherUiTest.waitForSetupWizardDismissal();
AbstractLauncherUiTest.verifyKeyguardInvisible();
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
index f6368b0..f51f286 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
@@ -92,7 +92,7 @@
startTestActivity(2);
startTestActivity(3);
- if (mLauncher.isTablet()) {
+ if (mLauncher.isTablet() && !mLauncher.isGridOnlyOverviewEnabled()) {
mLauncher.goHome().switchToOverview().getOverviewActions()
.clickSplit()
.getTestActivityTask(2)
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index d45c225..4075c55 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -179,6 +179,8 @@
@PortraitLandscape
@PlatinumTest(focusArea = "launcher")
public void testOverviewActions() throws Exception {
+ assumeFalse("Skipping Overview Actions tests for grid only overview",
+ mLauncher.isTablet() && mLauncher.isGridOnlyOverviewEnabled());
// Experimenting for b/165029151:
final Overview overview = mLauncher.goHome().switchToOverview();
if (overview.hasTasks()) overview.dismissAllTasks();
@@ -334,7 +336,6 @@
@Test
@PortraitLandscape
@NavigationModeSwitch
- @PlatinumTest(focusArea = "launcher")
public void testPressBack() throws Exception {
InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
READ_DEVICE_CONFIG_PERMISSION);
@@ -377,7 +378,9 @@
// Test opening the task.
overview.getCurrentTask().open();
assertTrue("Test activity didn't open from Overview",
- mDevice.wait(Until.hasObject(By.pkg(getAppPackageName()).text("TestActivity10")),
+ mDevice.wait(Until.hasObject(By.pkg(getAppPackageName()).text(
+ mLauncher.isGridOnlyOverviewEnabled() ? "TestActivity12"
+ : "TestActivity13")),
DEFAULT_UI_TIMEOUT));
// Scroll the task offscreen as it is now first
@@ -398,16 +401,17 @@
(Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet(
launcher)) <= 1)));
- // Test dismissing more tasks.
- assertTrue("Launcher internal state didn't remain in Overview",
- isInState(() -> LauncherState.OVERVIEW));
- overview.getCurrentTask().dismiss();
- assertTrue("Launcher internal state didn't remain in Overview",
- isInState(() -> LauncherState.OVERVIEW));
- overview.getCurrentTask().dismiss();
- executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple dismissals",
- (Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet(
- launcher)) <= 1)));
+ // TODO(b/308841019): Re-enable after fixing Overview jank when dismiss
+// // Test dismissing more tasks.
+// assertTrue("Launcher internal state didn't remain in Overview",
+// isInState(() -> LauncherState.OVERVIEW));
+// overview.getCurrentTask().dismiss();
+// assertTrue("Launcher internal state didn't remain in Overview",
+// isInState(() -> LauncherState.OVERVIEW));
+// overview.getCurrentTask().dismiss();
+// executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple dismissals",
+// (Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet(
+// launcher)) <= 1)));
// Test dismissing all tasks.
mLauncher.goHome().switchToOverview().dismissAllTasks();
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index acbb58f..ee0fbb8 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -143,7 +143,7 @@
startTestActivity(2);
startTestActivity(3);
- if (mLauncher.isTablet()) {
+ if (mLauncher.isTablet() && !mLauncher.isGridOnlyOverviewEnabled()) {
mLauncher.goHome().switchToOverview().getOverviewActions()
.clickSplit()
.getTestActivityTask(2)
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 39f1477..138e1b3 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -133,7 +133,7 @@
<string name="widgets_list_closed" msgid="6141506579418771922">"ವಿಜೆಟ್ ಪಟ್ಟಿಯನ್ನು ಮುಚ್ಚಲಾಗಿದೆ"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಸೇರಿಸಿ"</string>
<string name="action_move_here" msgid="2170188780612570250">"ಐಟಂ ಇಲ್ಲಿಗೆ ಸರಿಸಿ"</string>
- <string name="item_added_to_workspace" msgid="4211073925752213539">"ಮುಖಪುಟ ಪರದೆಗೆ ಐಟಂ ಸೇರಿಸಲಾಗಿದೆ"</string>
+ <string name="item_added_to_workspace" msgid="4211073925752213539">"ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಐಟಂ ಸೇರಿಸಲಾಗಿದೆ"</string>
<string name="item_removed" msgid="851119963877842327">"ಐಟಂ ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
<string name="undo" msgid="4151576204245173321">"ರದ್ದುಮಾಡಿ"</string>
<string name="action_move" msgid="4339390619886385032">"ಐಟಂ ಸರಿಸಿ"</string>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 883c379..e2e528c 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -22,7 +22,6 @@
import static com.android.launcher3.config.FeatureFlags.ENABLE_ICON_LABEL_AUTO_SCALING;
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
import static com.android.launcher3.icons.BitmapInfo.FLAG_NO_BADGE;
-import static com.android.launcher3.icons.BitmapInfo.FLAG_SKIP_USER_BADGE;
import static com.android.launcher3.icons.BitmapInfo.FLAG_THEMED;
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INCREMENTAL_DOWNLOAD_ACTIVE;
@@ -165,8 +164,6 @@
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mHideBadge = false;
@ViewDebug.ExportedProperty(category = "launcher")
- private boolean mSkipUserBadge = false;
- @ViewDebug.ExportedProperty(category = "launcher")
private boolean mIsIconVisible = true;
@ViewDebug.ExportedProperty(category = "launcher")
private int mTextColor;
@@ -269,10 +266,6 @@
mHideBadge = hideBadge;
}
- public void setSkipUserBadge(boolean skipUserBadge) {
- mSkipUserBadge = skipUserBadge;
- }
-
/**
* Resets the view so it can be recycled.
*/
@@ -301,7 +294,7 @@
}
}
- private void animateDotScale(float... dotScales) {
+ public void animateDotScale(float... dotScales) {
cancelDotScaleAnim();
mDotScaleAnim = ObjectAnimator.ofFloat(this, DOT_SCALE_PROPERTY, dotScales);
mDotScaleAnim.addListener(new AnimatorListenerAdapter() {
@@ -402,9 +395,6 @@
if (mHideBadge || mDisplay == DISPLAY_SEARCH_RESULT_SMALL) {
flags |= FLAG_NO_BADGE;
}
- if (mSkipUserBadge) {
- flags |= FLAG_SKIP_USER_BADGE;
- }
FastBitmapDrawable iconDrawable = info.newIcon(getContext(), flags);
mDotParams.appColor = iconDrawable.getIconColor();
mDotParams.dotColor = Themes.getAttrColor(getContext(), R.attr.notificationDotColor);
@@ -656,7 +646,7 @@
return mForceHideDot;
}
- private boolean hasDot() {
+ public boolean hasDot() {
return mDotInfo != null;
}
diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java
index 8ec5c18..8ff030e 100644
--- a/src/com/android/launcher3/ExtendedEditText.java
+++ b/src/com/android/launcher3/ExtendedEditText.java
@@ -101,8 +101,14 @@
}
public void hideKeyboard() {
+ hideKeyboard(/* clearFocus= */ true);
+ }
+
+ public void hideKeyboard(boolean clearFocus) {
ActivityContext.lookupContext(getContext()).hideKeyboard();
- clearFocus();
+ if (clearFocus) {
+ clearFocus();
+ }
}
protected void onKeyboardShown() {
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 4f8caab..aa06089 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -334,21 +334,21 @@
val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_END_SCALE_PERCENT =
nonRestorableItem(
"pref_long_press_nav_handle_haptic_hint_end_scale_percent",
- 50,
+ 100,
EncryptionType.MOVE_TO_DEVICE_PROTECTED
)
@JvmField
val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_SCALE_EXPONENT =
nonRestorableItem(
"pref_long_press_nav_handle_haptic_hint_scale_exponent",
- 2,
+ 1,
EncryptionType.MOVE_TO_DEVICE_PROTECTED
)
@JvmField
val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_ITERATIONS =
nonRestorableItem(
"pref_long_press_nav_handle_haptic_hint_iterations",
- 40,
+ 50,
EncryptionType.MOVE_TO_DEVICE_PROTECTED
)
@JvmField
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 84d3805..2315111 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -49,6 +49,7 @@
import android.animation.ValueAnimator;
import android.util.FloatProperty;
import android.view.View;
+import android.view.ViewGroup;
import android.view.animation.Interpolator;
import com.android.launcher3.LauncherState.PageAlphaProvider;
@@ -164,6 +165,8 @@
state.hasFlag(FLAG_HOTSEAT_INACCESSIBLE)
? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+ hotseat.setDescendantFocusability(state.hasFlag(FLAG_HOTSEAT_INACCESSIBLE)
+ ? ViewGroup.FOCUS_BLOCK_DESCENDANTS : ViewGroup.FOCUS_BEFORE_DESCENDANTS);
Interpolator translationInterpolator =
config.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT);
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index 005e6df..7baf7d3 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -27,7 +27,6 @@
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.config.FeatureFlags;
@@ -213,6 +212,7 @@
BubbleTextView icon = (BubbleTextView) holder.itemView;
icon.reset();
icon.applyFromApplicationInfo(adapterItem.itemInfo);
+ icon.setOnFocusChangeListener(mIconFocusListener);
break;
}
case VIEW_TYPE_EMPTY_SEARCH: {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index c783ee1..73861c1 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -119,6 +119,10 @@
getReleaseFlag(301680992, "CUSTOM_LPNH_THRESHOLDS", DISABLED,
"Add dev options to customize the LPNH trigger slop and milliseconds");
+ public static final BooleanFlag ANIMATE_LPNH =
+ getReleaseFlag(308693847, "ANIMATE_LPNH", TEAMFOOD,
+ "Animates navbar when long pressing");
+
public static final IntFlag LPNH_SLOP_PERCENTAGE =
getIntFlag(301680992, "LPNH_SLOP_PERCENTAGE", 100,
"Controls touch slop percentage for lpnh");
@@ -271,7 +275,7 @@
"Enables long pressing on the bottom bar nav handle to trigger events.");
public static final BooleanFlag ENABLE_SEARCH_HAPTIC_HINT =
- getReleaseFlag(303023676, "ENABLE_SEARCH_HAPTIC_HINT", TEAMFOOD,
+ getReleaseFlag(303023676, "ENABLE_SEARCH_HAPTIC_HINT", ENABLED,
"Enables haptic hint when long pressing on the bottom bar nav handle.");
// TODO(Block 17): Clean up flags
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index 18200f6..69fa673 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -169,6 +169,9 @@
LauncherPrefs.get(getContext())
.put(THEMED_ICONS, values.getAsBoolean(BOOLEAN_VALUE));
getContext().getContentResolver().notifyChange(uri, null);
+ mActivePreviews.values().forEach(observer ->
+ observer.renderer.refreshIcons()
+ );
return 1;
}
default:
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 3330448..346f644 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -35,9 +35,12 @@
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps;
import android.content.res.TypedArray;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
@@ -76,6 +79,7 @@
import com.android.launcher3.celllayout.CellPosMapper;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
@@ -83,6 +87,7 @@
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.InstallSessionHelper;
@@ -188,6 +193,8 @@
private final SparseIntArray mWallpaperColorResources;
private final SparseArray<Size> mLauncherWidgetSpanInfo;
+ private final Map<BubbleTextView, WorkspaceItemInfo> mIcons = new HashMap<>();
+
public LauncherPreviewRenderer(Context context,
InvariantDeviceProfile idp,
WallpaperColors wallpaperColorsOverride,
@@ -366,11 +373,43 @@
return CellPosMapper.DEFAULT;
}
+ /**
+ * Refreshes icon to update based on resource changes.
+ */
+ public void refreshIcons() {
+ mUiHandler.post(() -> {
+ IconProvider iconProvider = null;
+ int iconDpi = -1;
+ for (Map.Entry<BubbleTextView, WorkspaceItemInfo> entry : mIcons.entrySet()) {
+ BubbleTextView icon = entry.getKey();
+ ItemInfoWithIcon info = entry.getValue();
+ // get monochrome themed icon if it was not initially cached
+ if (info.bitmap.getMono() == null) {
+ if (iconProvider == null || iconDpi == -1) {
+ LauncherAppState appState = LauncherAppState.getInstance(mContext);
+ iconProvider = appState.getIconProvider();
+ iconDpi = appState.getInvariantDeviceProfile().fillResIconDpi;
+ }
+ LauncherActivityInfo activityInfo = mContext.getSystemService(
+ LauncherApps.class)
+ .resolveActivity(info.getIntent(), info.user);
+ Drawable iconDrawable = iconProvider.getIcon(activityInfo, iconDpi);
+ LauncherIcons iconFactory = LauncherIcons.obtain(mContext);
+ info.bitmap = iconFactory.createBadgedIconBitmap(iconDrawable);
+ }
+ // update icon based on whether themed icon is enabled
+ icon.reapplyItemInfo(info);
+ }
+ }
+ );
+ }
+
private void inflateAndAddIcon(WorkspaceItemInfo info) {
CellLayout screen = mWorkspaceScreens.get(info.screenId);
BubbleTextView icon = (BubbleTextView) mHomeElementInflater.inflate(
R.layout.app_icon, screen, false);
icon.applyFromWorkspaceItem(info);
+ mIcons.put(icon, info);
addInScreenFromBind(icon, info);
}
@@ -477,6 +516,8 @@
currentWorkspaceItems, otherWorkspaceItems);
filterCurrentWorkspaceItems(currentScreenIds, dataModel.appWidgets, currentAppWidgets,
otherAppWidgets);
+
+ mIcons.clear();
for (ItemInfo itemInfo : currentWorkspaceItems) {
switch (itemInfo.itemType) {
case Favorites.ITEM_TYPE_APPLICATION:
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index 683354b..1bac765 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -201,6 +201,13 @@
}
}
+ /**
+ * Refreshes icon to update based on resource changes.
+ */
+ public void refreshIcons() {
+ mRenderer.refreshIcons();
+ }
+
/***
* Generates a new context overriding the theme color and the display size without affecting the
* main application context
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 6b08153..685e4f1 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -415,8 +415,7 @@
private void orientAboutObject(boolean allowAlignLeft, boolean allowAlignRight) {
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- int extraVerticalSpace = mArrowHeight + mArrowOffsetVertical
- + getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding);
+ int extraVerticalSpace = mArrowHeight + mArrowOffsetVertical + getExtraVerticalOffset();
// The margins are added after we call this method, so we need to account for them here.
int numVisibleChildren = 0;
for (int i = getChildCount() - 1; i >= 0; --i) {
@@ -632,6 +631,10 @@
mOpenCloseAnimator.start();
}
+ public int getExtraVerticalOffset() {
+ return getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding);
+ }
+
protected AnimatorSet getOpenCloseAnimator(boolean isOpening, int scaleDuration,
int fadeStartDelay, int fadeDuration, int childFadeStartDelay, int childFadeDuration,
Interpolator interpolator) {
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 228af4c..650fbcc 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -18,7 +18,6 @@
import static android.provider.Settings.Global.DEVELOPMENT_SETTINGS_ENABLED;
-import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS;
import static androidx.preference.PreferenceFragmentCompat.ARG_PREFERENCE_ROOT;
import static com.android.launcher3.BuildConfig.IS_DEBUG_DEVICE;
@@ -34,7 +33,6 @@
import android.view.MenuItem;
import android.view.View;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.view.WindowCompat;
@@ -290,8 +288,6 @@
if (highlighter != null) {
getView().postDelayed(highlighter, DELAY_HIGHLIGHT_DURATION_MILLIS);
mPreferenceHighlighted = true;
- } else {
- requestAccessibilityFocus(getListView());
}
}
@@ -350,14 +346,5 @@
list, position, screen.findPreference(mHighLightKey))
: null;
}
-
- private void requestAccessibilityFocus(@NonNull final RecyclerView rv) {
- rv.post(() -> {
- if (!rv.hasFocus() && rv.getChildCount() > 0) {
- rv.getChildAt(0)
- .performAccessibilityAction(ACTION_ACCESSIBILITY_FOCUS, null);
- }
- });
- }
}
}
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index eb45ded..3e80e6b 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -158,7 +158,6 @@
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
public static final String TWO_TASKBAR_LONG_CLICKS = "b/262282528";
public static final String ICON_MISSING = "b/282963545";
- public static final String SPLIT_LEAK = "b/302551868";
public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
diff --git a/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java b/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java
new file mode 100644
index 0000000..80f73cb
--- /dev/null
+++ b/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 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.launcher3.allapps;
+
+import static com.android.launcher3.ui.TaplTestsLauncher3.initialize;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.view.KeyEvent;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.tapl.HomeAllApps;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TaplKeyboardFocusTest extends AbstractLauncherUiTest {
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ initialize(this);
+ }
+
+ @Test
+ public void testAllAppsFocusApp() {
+ final HomeAllApps allApps = mLauncher.goHome().switchToAllApps();
+ assertTrue("Launcher internal state is not All Apps",
+ isInState(() -> LauncherState.ALL_APPS));
+ allApps.freeze();
+ try {
+ mLauncher.pressAndHoldKeyCode(KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ executeOnLauncher(launcher -> assertNotNull("No focused child.",
+ launcher.getAppsView().getActiveRecyclerView().getApps().getFocusedChild()));
+ } finally {
+ allApps.unfreeze();
+ }
+ }
+
+ @Test
+ public void testAllAppsExitSearchAndFocusApp() {
+ final HomeAllApps allApps = mLauncher.goHome().switchToAllApps();
+ assertTrue("Launcher internal state is not All Apps",
+ isInState(() -> LauncherState.ALL_APPS));
+ allApps.freeze();
+ try {
+ executeOnLauncher(launcher -> launcher.getAppsView().getSearchView().requestFocus());
+ waitForLauncherCondition("Search view does not have focus.",
+ launcher -> launcher.getAppsView().getSearchView().hasFocus());
+
+ mLauncher.pressAndHoldKeyCode(KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ executeOnLauncher(launcher -> assertNotNull("No focused child.",
+ launcher.getAppsView().getActiveRecyclerView().getApps().getFocusedChild()));
+ } finally {
+ allApps.unfreeze();
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 4184868..9bfafcf 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -187,7 +187,7 @@
Utilities.enableRunningInTestHarnessForTests();
mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand(
TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString())
- .getString("result"));
+ .getString("result"));
mLauncher.setOnSettledStateAction(
containerType -> executeOnLauncher(
launcher ->
@@ -248,6 +248,7 @@
public void setUp() throws Exception {
mLauncher.onTestStart();
+ waitForSetupWizardDismissal();
if (TestStabilityRule.isPresubmit()) {
aggressivelyUnlockSysUi();
} else {
@@ -308,6 +309,36 @@
Log.d(TAG, "Keyguard is not visible");
}
+ // b/309008042
+ private static boolean sFirstTimeWaitingForWizard = true;
+
+ // b/309008042
+ static {
+ waitForSetupWizardDismissal();
+ }
+
+ // b/309008042
+ // TODO(309471958) Productize killing/dismissal of setup wizard.
+ /** Waits for setup wizard to go away. */
+ public static void waitForSetupWizardDismissal() {
+ if (sFirstTimeWaitingForWizard && TestStabilityRule.isPresubmit()) {
+ try {
+ UiDevice.getInstance(getInstrumentation()).executeShellCommand(
+ "am force-stop com.google.android.setupwizard");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ final boolean wizardDismissed = TestHelpers.wait(
+ Until.gone(By.pkg("com.google.android.setupwizard").depth(0)),
+ sFirstTimeWaitingForWizard ? 120000 : 0);
+ sFirstTimeWaitingForWizard = false;
+ // b/309496273
+// Assert.assertTrue("Setup wizard is still visible",
+// wizardDismissed);
+ }
+
public static void verifyKeyguardInvisible() {
final boolean keyguardAlreadyVisible = sSeenKeyguard;
@@ -422,6 +453,7 @@
// flakiness.
protected void waitForLauncherCondition(
String message, Function<Launcher, Boolean> condition, long timeout) {
+ waitForSetupWizardDismissal();
verifyKeyguardInvisible();
if (!TestHelpers.isInLauncherProcess()) return;
Wait.atMost(message, () -> getFromLauncher(condition), timeout, mLauncher);
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index a85b6bd..770fe14 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -25,6 +25,7 @@
import androidx.test.uiautomator.UiObject2;
import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
@@ -201,7 +202,8 @@
OverviewTask task = getCurrentTask();
mLauncher.assertNotNull("current task is null", task);
mLauncher.scrollLeftByDistance(verifyActiveContainer(),
- task.getVisibleWidth() + mLauncher.getOverviewPageSpacing());
+ mLauncher.getRealDisplaySize().x - task.getUiObject().getVisibleBounds().left
+ + mLauncher.getOverviewPageSpacing());
try (LauncherInstrumentation.Closable c2 =
mLauncher.addContextLayer("scrolled task off screen")) {
@@ -231,14 +233,14 @@
final List<UiObject2> taskViews = getTasks();
mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
- // taskViews contains up to 3 task views: the 'main' (having the widest visible part) one
- // in the center, and parts of its right and left siblings. Find the main task view by
- // its width.
- final UiObject2 widestTask = Collections.max(taskViews,
- (t1, t2) -> Integer.compare(mLauncher.getVisibleBounds(t1).width(),
- mLauncher.getVisibleBounds(t2).width()));
-
- return new OverviewTask(mLauncher, widestTask, this);
+ final List<OverviewTask> overviewTasks = taskViews.stream().map(
+ task -> new OverviewTask(mLauncher, task, this)).toList();
+ // The widest, and most top-right task should be the current task
+ return Collections.max(overviewTasks,
+ Comparator.comparingInt(OverviewTask::getVisibleWidth)
+ .thenComparingInt(OverviewTask::getTaskCenterX)
+ .thenComparing(
+ Comparator.comparing(OverviewTask::getTaskCenterY).reversed()));
}
/** Returns an overview task matching TestActivity {@param activityNumber}. */
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 307f192..17169b3 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1608,8 +1608,11 @@
scroll(
container,
Direction.LEFT,
- new Rect(leftGestureMargin, 0,
- containerRect.width() - distance - rightGestureMarginInContainer, 0),
+ new Rect(leftGestureMargin,
+ 0,
+ Math.max(containerRect.width() - distance - leftGestureMargin,
+ rightGestureMarginInContainer),
+ 0),
10,
true);
}
@@ -1782,7 +1785,7 @@
TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
- boolean isGridOnlyOverviewEnabled() {
+ public boolean isGridOnlyOverviewEnabled() {
return getTestInfo(TestProtocol.REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW).getBoolean(
TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
@@ -2225,7 +2228,7 @@
int bottomBound = Math.min(
containerBounds.bottom,
getRealDisplaySize().y - getImeInsets().bottom);
- int y = (bottomBound - containerBounds.top) / 2;
+ int y = (bottomBound + containerBounds.top) / 2;
// Do not tap in the status bar.
y = Math.max(y, getWindowInsets().top);
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 06fac48..8a34f0d 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -73,10 +73,13 @@
* Calculates the visible height for split tasks, containing 2 snapshot tiles and a divider.
*/
private int getCombinedSplitTaskHeight() {
- UiObject2 taskSnapshot1 =
- mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_1);
- UiObject2 taskSnapshot2 =
- mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_2);
+ UiObject2 taskSnapshot1 = findObjectInTask(TASK_SNAPSHOT_1);
+ UiObject2 taskSnapshot2 = findObjectInTask(TASK_SNAPSHOT_2);
+
+ // If the split task is partly off screen, taskSnapshot1 can be invisible.
+ if (taskSnapshot1 == null) {
+ return taskSnapshot2.getVisibleBounds().height();
+ }
int top = Math.min(
taskSnapshot1.getVisibleBounds().top, taskSnapshot2.getVisibleBounds().top);
@@ -102,10 +105,8 @@
* Calculates the visible width for split tasks, containing 2 snapshot tiles and a divider.
*/
private int getCombinedSplitTaskWidth() {
- UiObject2 taskSnapshot1 =
- mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_1);
- UiObject2 taskSnapshot2 =
- mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_2);
+ UiObject2 taskSnapshot1 = findObjectInTask(TASK_SNAPSHOT_1);
+ UiObject2 taskSnapshot2 = findObjectInTask(TASK_SNAPSHOT_2);
int left = Math.min(
taskSnapshot1.getVisibleBounds().left, taskSnapshot2.getVisibleBounds().left);
@@ -116,11 +117,15 @@
}
int getTaskCenterX() {
- return mTask.getVisibleCenter().x;
+ return mTask.getParent().getVisibleCenter().x;
+ }
+
+ int getTaskCenterY() {
+ return mTask.getParent().getVisibleCenter().y;
}
float getExactCenterX() {
- return mTask.getVisibleBounds().exactCenterX();
+ return mTask.getParent().getVisibleBounds().exactCenterX();
}
UiObject2 getUiObject() {
@@ -144,7 +149,8 @@
boolean taskWasFocused = mLauncher.isTablet() && getVisibleHeight() == mLauncher
.getFocusedTaskHeightForTablet();
- List<Integer> originalTasksCenterX = getCurrentTasksCenterXList();
+ List<Integer> originalTasksCenterX =
+ getCurrentTasksCenterXList().stream().sorted().toList();
boolean isClearAllVisibleBeforeDismiss = mOverview.isClearAllVisible();
dismissBySwipingUp();
@@ -155,7 +161,8 @@
mOverview.getFocusedTaskForTablet());
}
if (!isClearAllVisibleBeforeDismiss) {
- List<Integer> currentTasksCenterX = getCurrentTasksCenterXList();
+ List<Integer> currentTasksCenterX =
+ getCurrentTasksCenterXList().stream().sorted().toList();
if (originalTasksCenterX.size() == currentTasksCenterX.size()) {
// Check for the same number of visible tasks before and after to
// avoid asserting on cases of shifting all tasks to close the distance
@@ -173,7 +180,7 @@
// Dismiss the task via flinging it up.
final Rect taskBounds = mLauncher.getVisibleBounds(mTask);
final int centerX = taskBounds.centerX();
- final int centerY = taskBounds.centerY();
+ final int centerY = taskBounds.bottom - 1;
mLauncher.executeAndWaitForLauncherEvent(
() -> mLauncher.linearGesture(centerX, centerY, centerX, 0, 10, false,
LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER),
@@ -253,6 +260,10 @@
}
boolean isTaskSplit() {
- return mLauncher.findObjectInContainer(mTask.getParent(), "bottomright_snapshot") != null;
+ return findObjectInTask(TASK_SNAPSHOT_2) != null;
+ }
+
+ private UiObject2 findObjectInTask(String resName) {
+ return mTask.getParent().findObject(mLauncher.getOverviewObjectSelector(resName));
}
}