Merge "Import translations. DO NOT MERGE ANYWHERE" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 9080284..af175ce 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -83,3 +83,10 @@
description: "Enables two pane widget picker for unfolded foldables"
bug: "313922374"
}
+
+flag {
+ name: "enable_tablet_two_pane_picker_v2"
+ namespace: "launcher"
+ description: "Enables full width two pane widget picker for tablets in landscape and portrait"
+ bug: "315055849"
+}
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index 5a9e147..8240f11 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -138,7 +138,7 @@
}
}
-// Next value 54
+// Next value 55
enum Attribute {
option allow_alias = true;
@@ -200,6 +200,7 @@
DATA_SOURCE_APPSEARCH_CATEGORY_SRP_PREVIEW = 48;
DATA_SOURCE_APPSEARCH_ENTITY_SRP_PREVIEW = 49;
DATA_SOURCE_AIAI_SEARCH_ROOT = 47;
+ DATA_SOURCE_LAUNCHER = 54;
// Web suggestions provided by AGA
ALL_APPS_SEARCH_RESULT_WEB_SUGGEST = 39;
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index 0fda0bf..fe517fa 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -31,7 +31,7 @@
android:layout_height="1dp"
android:layout_weight="1" />
- <Button
+ <com.android.quickstep.views.ScreenshotActionButton
android:id="@+id/action_screenshot"
style="@style/OverviewActionButton"
android:layout_width="wrap_content"
@@ -40,17 +40,12 @@
android:text="@string/action_screenshot"
android:theme="@style/ThemeControlHighlightWorkspaceColor" />
- <Space
- android:id="@+id/action_split_space"
- android:layout_width="@dimen/overview_actions_button_spacing"
- android:layout_height="1dp"
- android:visibility="gone" />
-
- <Button
+ <com.android.quickstep.views.SplitActionButton
android:id="@+id/action_split"
style="@style/OverviewActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/overview_actions_button_spacing"
android:text="@string/action_split"
android:theme="@style/ThemeControlHighlightWorkspaceColor"
android:visibility="gone" />
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index d6ab54e..8db63e3 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -55,6 +55,7 @@
import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
+import static com.android.launcher3.testing.shared.TestProtocol.WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE;
import static com.android.launcher3.util.DisplayController.isTransientTaskbar;
import static com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR;
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
@@ -120,6 +121,7 @@
import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorListeners;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.model.data.ItemInfo;
@@ -1651,6 +1653,15 @@
if (launcherIsForceInvisibleOrOpening) {
addCujInstrumentation(anim, playFallBackAnimation
? CUJ_APP_CLOSE_TO_HOME_FALLBACK : CUJ_APP_CLOSE_TO_HOME);
+
+ anim.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ AccessibilityManagerCompat.sendTestProtocolEventToTest(
+ mLauncher, WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE);
+ }
+ });
+
// Only register the content animation for cancellation when state changes
mLauncher.getStateManager().setCurrentAnimation(anim);
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 221ce48..f801b3b 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -106,10 +106,10 @@
});
return response;
- case TestProtocol.REQUEST_STASHED_TASKBAR_HEIGHT: {
+ case TestProtocol.REQUEST_TASKBAR_FROM_NAV_THRESHOLD: {
final Resources resources = mContext.getResources();
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
- resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size));
+ resources.getDimensionPixelSize(R.dimen.taskbar_from_nav_threshold));
return response;
}
diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java
index 20a751b..1b3f598 100644
--- a/quickstep/src/com/android/quickstep/TaskIconCache.java
+++ b/quickstep/src/com/android/quickstep/TaskIconCache.java
@@ -31,7 +31,6 @@
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.SparseArray;
-import android.view.accessibility.AccessibilityManager;
import androidx.annotation.WorkerThread;
@@ -45,6 +44,7 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
import com.android.launcher3.util.DisplayController.Info;
+import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.Preconditions;
import com.android.quickstep.util.CancellableTask;
import com.android.quickstep.util.TaskKeyLruCache;
@@ -62,7 +62,6 @@
public class TaskIconCache implements DisplayInfoChangeListener {
private final Executor mBgExecutor;
- private final AccessibilityManager mAccessibilityManager;
private final Context mContext;
private final TaskKeyLruCache<TaskCacheEntry> mIconCache;
@@ -79,7 +78,6 @@
public TaskIconCache(Context context, Executor bgExecutor, IconProvider iconProvider) {
mContext = context;
mBgExecutor = bgExecutor;
- mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
mIconProvider = iconProvider;
Resources res = context.getResources();
@@ -238,14 +236,11 @@
if ((index = mDefaultIcons.indexOfKey(userId)) >= 0) {
return mDefaultIcons.valueAt(index).newIcon(mContext);
} else {
- try (BaseIconFactory li = getIconFactory()) {
- BitmapInfo info = mDefaultIconBase.withFlags(
- li.getBitmapFlagOp(new IconOptions()
- .setUser(UserCache.INSTANCE.get(mContext)
- .getUserInfo(UserHandle.of(userId)))));
- mDefaultIcons.put(userId, info);
- return info.newIcon(mContext);
- }
+ BitmapInfo info = mDefaultIconBase.withFlags(
+ UserCache.INSTANCE.get(mContext).getUserInfo(UserHandle.of(userId))
+ .applyBitmapInfoFlags(FlagOp.NO_OP));
+ mDefaultIcons.put(userId, info);
+ return info.newIcon(mContext);
}
}
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
index 57c05e9..4d47f07 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
@@ -56,5 +56,5 @@
* Called when nav handle gesture is finished by the user lifting their finger or the system
* cancelling the touch for some other reason.
*/
- public void onTouchFinished() {}
+ public void onTouchFinished(String reason) {}
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index 0127cc9..0a558e2 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -81,7 +81,7 @@
if (mDelegate.allowInterceptByParent()) {
handleMotionEvent(ev);
} else if (MAIN_EXECUTOR.getHandler().hasCallbacks(mTriggerLongPress)) {
- cancelLongPress();
+ cancelLongPress("intercept disallowed by child input consumer");
}
if (mState != STATE_ACTIVE) {
@@ -113,10 +113,11 @@
float dy = ev.getY() - mCurrentDownEvent.getY();
double distanceSquared = (dx * dx) + (dy * dy);
if (distanceSquared > touchSlopSquared) {
- cancelLongPress();
+ cancelLongPress("touch slop passed");
}
}
- case MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> cancelLongPress();
+ case MotionEvent.ACTION_UP -> cancelLongPress("touch action up");
+ case MotionEvent.ACTION_CANCEL -> cancelLongPress("touch action cancel");
}
// If the gesture is deep press then trigger long press asap
@@ -158,9 +159,9 @@
}
}
- private void cancelLongPress() {
+ private void cancelLongPress(String reason) {
MAIN_EXECUTOR.getHandler().removeCallbacks(mTriggerLongPress);
- mNavHandleLongPressHandler.onTouchFinished();
+ mNavHandleLongPressHandler.onTouchFinished(reason);
}
private boolean isInNavBarHorizontalArea(float x) {
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
index 423ba43..c013483 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
@@ -93,6 +93,7 @@
private var secondTaskId: Int = INVALID_TASK_ID
private var initialIntent: Intent? = null
private var secondIntent: Intent? = null
+ private var widgetSecondIntent: Intent? = null
private var initialUser: UserHandle? = null
private var secondUser: UserHandle? = null
private var initialPendingIntent: PendingIntent? = null
@@ -167,6 +168,16 @@
secondUser = pendingIntent.creatorUserHandle
}
+ /**
+ * Similar to [setSecondTask] except this is to be called for widgets which can pass through
+ * an extra intent from their RemoteResponse.
+ * See [android.widget.RemoteViews.RemoteResponse.getLaunchOptions].first
+ */
+ fun setSecondWidget(pendingIntent: PendingIntent, widgetIntent: Intent?) {
+ setSecondTask(pendingIntent)
+ widgetSecondIntent = widgetIntent
+ }
+
private fun getShortcutInfo(intent: Intent?, user: UserHandle?): ShortcutInfo? {
val intentPackage = intent?.getPackage() ?: return null
val shortcutId = intent.getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID)
@@ -241,6 +252,7 @@
secondTaskId,
initialPendingIntent,
secondPendingIntent,
+ widgetSecondIntent,
initialUser?.identifier ?: -1,
secondUser?.identifier ?: -1,
initialShortcut,
@@ -257,7 +269,8 @@
* Note that both [initialIntent] and [secondIntent] will be nullified on method return
*
* One caveat is that if [secondPendingIntent] is set, we will use that and *not* attempt to
- * convert [secondIntent]
+ * convert [secondIntent].
+ * This also leaves [widgetSecondIntent] untouched.
*/
private fun convertIntentsToFinalTypes() {
initialShortcut = getShortcutInfo(initialIntent, initialUser)
@@ -343,6 +356,7 @@
var secondTaskId: Int = INVALID_TASK_ID,
var initialPendingIntent: PendingIntent? = null,
var secondPendingIntent: PendingIntent? = null,
+ var widgetSecondIntent: Intent? = null,
var initialUserId: Int = -1,
var secondUserId: Int = -1,
var initialShortcut: ShortcutInfo? = null,
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 145707b..8b27a85 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -32,6 +32,7 @@
import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_SHORTCUT;
import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_TASK;
import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
+import static com.android.wm.shell.common.split.SplitScreenConstants.KEY_EXTRA_WIDGET_INTENT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
import android.animation.Animator;
@@ -355,6 +356,10 @@
mSplitSelectDataHolder.setSecondTask(pendingIntent);
}
+ public void setSecondWidget(PendingIntent pendingIntent, Intent widgetIntent) {
+ mSplitSelectDataHolder.setSecondWidget(pendingIntent, widgetIntent);
+ }
+
/**
* To be called when we want to launch split pairs from Overview. Split can be initiated from
* either Overview or home, or all apps. Either both taskIds are set, or a pending intent + a
@@ -380,11 +385,13 @@
ShortcutInfo secondShortcut = launchData.getSecondShortcut();
PendingIntent firstPI = launchData.getInitialPendingIntent();
PendingIntent secondPI = launchData.getSecondPendingIntent();
+ Intent widgetIntent = launchData.getWidgetSecondIntent();
int firstUserId = launchData.getInitialUserId();
int secondUserId = launchData.getSecondUserId();
int initialStagePosition = launchData.getInitialStagePosition();
Bundle optionsBundle = options1.toBundle();
-
+ Bundle extrasBundle = new Bundle(1);
+ extrasBundle.putParcelable(KEY_EXTRA_WIDGET_INTENT, widgetIntent);
if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
final RemoteTransition remoteTransition = getShellRemoteTransition(firstTaskId,
secondTaskId, callback, "LaunchSplitPair");
@@ -396,7 +403,7 @@
case SPLIT_TASK_PENDINGINTENT ->
mSystemUiProxy.startIntentAndTask(secondPI, secondUserId, optionsBundle,
- firstTaskId, null /*options2*/, initialStagePosition, snapPosition,
+ firstTaskId, extrasBundle, initialStagePosition, snapPosition,
remoteTransition, shellInstanceId);
case SPLIT_TASK_SHORTCUT ->
@@ -411,9 +418,9 @@
case SPLIT_PENDINGINTENT_PENDINGINTENT ->
mSystemUiProxy.startIntents(firstPI, firstUserId, firstShortcut,
- optionsBundle, secondPI, secondUserId, secondShortcut,
- null /*options2*/, initialStagePosition, snapPosition,
- remoteTransition, shellInstanceId);
+ optionsBundle, secondPI, secondUserId, secondShortcut, extrasBundle,
+ initialStagePosition, snapPosition, remoteTransition,
+ shellInstanceId);
case SPLIT_SHORTCUT_TASK ->
mSystemUiProxy.startShortcutAndTask(firstShortcut, optionsBundle,
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index 9313342..e705285 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -72,7 +72,8 @@
* @return {@code true} if we can attempt launch the widget into split, {@code false} otherwise
* to allow launcher to handle the click
*/
- public boolean handleSecondWidgetSelectionForSplit(View view, PendingIntent pendingIntent) {
+ public boolean handleSecondWidgetSelectionForSplit(View view, PendingIntent pendingIntent,
+ Intent remoteResponseIntent) {
if (shouldIgnoreSecondSplitLaunch()) {
return false;
}
@@ -86,7 +87,7 @@
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
view.post(() -> {
- mController.setSecondTask(pendingIntent);
+ mController.setSecondWidget(pendingIntent, remoteResponseIntent);
// Convert original widgetView into bitmap to use for animation
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
diff --git a/quickstep/src/com/android/quickstep/views/ActionButton.kt b/quickstep/src/com/android/quickstep/views/ActionButton.kt
new file mode 100644
index 0000000..5c004cc
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/ActionButton.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.quickstep.views
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.Button
+
+/**
+ * A button on the Overview Actions Bar. Custom logic for hiding/showing each button type is handled
+ * in the respective subclass.
+ */
+open class ActionButton : Button {
+ private var mHiddenFlags = 0
+
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int
+ ) : super(context, attrs, defStyleAttr)
+
+ /**
+ * Updates the proper flags to indicate whether the button should be hidden.
+ *
+ * @param flag The flag to update.
+ * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
+ */
+ protected fun updateHiddenFlags(flag: Int, enable: Boolean) {
+ if (enable) {
+ mHiddenFlags = mHiddenFlags or flag
+ } else {
+ mHiddenFlags = mHiddenFlags and flag.inv()
+ }
+ val shouldBeVisible = mHiddenFlags == 0
+ this.visibility = if (shouldBeVisible) VISIBLE else GONE
+ }
+
+ /** Show/hide the button when the focused task is a single/pair. */
+ open fun updateForMultipleTasks(hasMultipleTasks: Boolean) {
+ // overridden in subclass, or else don't do anything
+ }
+
+ /** Show/hide the button depending on if the device is a tablet. */
+ open fun updateForTablet(isTablet: Boolean) {
+ // overridden in subclass, or else don't do anything
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index b549058..a5c94c5 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -22,7 +22,6 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
-import android.widget.Button;
import android.widget.FrameLayout;
import androidx.annotation.IntDef;
@@ -41,6 +40,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
/**
* View for showing action buttons in Overview
@@ -89,14 +90,11 @@
private static final int INDEX_SCROLL_ALPHA = 5;
private static final int NUM_ALPHAS = 6;
- public @interface SplitButtonHiddenFlags { }
- public static final int FLAG_IS_NOT_TABLET = 1 << 0;
-
- public @interface SplitButtonDisabledFlags { }
- public static final int FLAG_SINGLE_TASK = 1 << 0;
-
private MultiValueAlpha mMultiValueAlpha;
- private Button mSplitButton;
+
+ protected List<ActionButton> mActionButtons = new ArrayList<>();
+ private ScreenshotActionButton mScreenshotButton;
+ private SplitActionButton mSplitButton;
@ActionsHiddenFlags
private int mHiddenFlags;
@@ -104,12 +102,6 @@
@ActionsDisabledFlags
protected int mDisabledFlags;
- @SplitButtonHiddenFlags
- private int mSplitButtonHiddenFlags;
-
- @SplitButtonDisabledFlags
- private int mSplitButtonDisabledFlags;
-
@Nullable
protected T mCallbacks;
@@ -135,9 +127,12 @@
mMultiValueAlpha = new MultiValueAlpha(findViewById(R.id.action_buttons), NUM_ALPHAS);
mMultiValueAlpha.setUpdateVisibility(true);
- findViewById(R.id.action_screenshot).setOnClickListener(this);
+ mScreenshotButton = findViewById(R.id.action_screenshot);
+ mScreenshotButton.setOnClickListener(this);
+ mActionButtons.add(mScreenshotButton);
mSplitButton = findViewById(R.id.action_split);
mSplitButton.setOnClickListener(this);
+ mActionButtons.add(mSplitButton);
}
/**
@@ -201,40 +196,28 @@
}
boolean isEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
LayoutUtils.setViewEnabled(this, isEnabled);
- updateSplitButtonEnabledState();
}
/**
- * Updates the proper flags to indicate whether the "Split screen" button should be hidden.
- *
- * @param flag The flag to update.
- * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
+ * Updates flags to hide and show actions buttons when a grouped task (split screen) is focused.
+ * @param isGroupedTask True if the focused task is a grouped task.
*/
- public void updateSplitButtonHiddenFlags(@SplitButtonHiddenFlags int flag, boolean enable) {
- if (enable) {
- mSplitButtonHiddenFlags |= flag;
- } else {
- mSplitButtonHiddenFlags &= ~flag;
+ public void updateForGroupedTask(boolean isGroupedTask) {
+ for (ActionButton button : mActionButtons) {
+ // Update flags to show/hide buttons.
+ button.updateForMultipleTasks(isGroupedTask);
}
- if (mSplitButton == null) return;
- boolean shouldBeVisible = mSplitButtonHiddenFlags == 0;
- mSplitButton.setVisibility(shouldBeVisible ? VISIBLE : GONE);
- findViewById(R.id.action_split_space).setVisibility(shouldBeVisible ? VISIBLE : GONE);
}
/**
- * Updates the proper flags to indicate whether the "Split screen" button should be disabled.
- *
- * @param flag The flag to update.
- * @param enable Whether to enable the disable flag: True will cause view to be disabled.
+ * Updates flags to hide and show actions buttons depending on if the device is a tablet.
+ * @param isTablet True if the current device is a tablet.
*/
- public void updateSplitButtonDisabledFlags(@SplitButtonDisabledFlags int flag, boolean enable) {
- if (enable) {
- mSplitButtonDisabledFlags |= flag;
- } else {
- mSplitButtonDisabledFlags &= ~flag;
+ public void updateForTablet(boolean isTablet) {
+ for (ActionButton button : mActionButtons) {
+ // Update flags to show/hide buttons.
+ button.updateForTablet(isTablet);
}
- updateSplitButtonEnabledState();
}
public MultiProperty getContentAlpha() {
@@ -313,18 +296,4 @@
: R.drawable.ic_split_vertical;
mSplitButton.setCompoundDrawablesRelativeWithIntrinsicBounds(splitIconRes, 0, 0, 0);
}
-
- /**
- * Enables/disables the "Split" button based on the status of mSplitButtonDisabledFlags and
- * mDisabledFlags.
- */
- private void updateSplitButtonEnabledState() {
- if (mSplitButton == null) {
- return;
- }
- boolean isParentEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
- boolean shouldBeEnabled = mSplitButtonDisabledFlags == 0 && isParentEnabled;
- mSplitButton.setEnabled(shouldBeEnabled);
- }
-
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 7e1034b..c56b5bb 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -20,7 +20,6 @@
import static android.view.Surface.ROTATION_0;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;
-
import static com.android.app.animation.Interpolators.ACCELERATE;
import static com.android.app.animation.Interpolators.ACCELERATE_0_75;
import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
@@ -62,8 +61,6 @@
import static com.android.quickstep.util.TaskGridNavHelper.DIRECTION_UP;
import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA;
import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
-import static com.android.quickstep.views.OverviewActionsView.FLAG_IS_NOT_TABLET;
-import static com.android.quickstep.views.OverviewActionsView.FLAG_SINGLE_TASK;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_ACTIONS_IN_MENU;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_DESKTOP;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NON_ZERO_ROTATION;
@@ -3941,18 +3938,23 @@
}
/**
- * Hides all overview actions if current page is for split apps, shows otherwise
- * If actions are showing, we only show split option if
+ * Hides all overview actions if user is halfway through split selection, shows otherwise.
+ * We only show split option if:
+ * * Focused view is a single app
* * Device is large screen
- * * There are at least 2 tasks to invoke split
*/
private void updateCurrentTaskActionsVisibility() {
- boolean isCurrentSplit = getCurrentPageTaskView() instanceof GroupedTaskView;
- mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SCREEN, isCurrentSplit);
+ boolean isGroupedTask = getCurrentPageTaskView() != null
+ && getCurrentPageTaskView().containsMultipleTasks();
+ // Update flags to see if entire actions bar should be hidden.
+ mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SCREEN, isGroupedTask);
mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SELECT_ACTIVE, isSplitSelectionActive());
- mActionsView.updateSplitButtonHiddenFlags(FLAG_IS_NOT_TABLET,
- !mActivity.getDeviceProfile().isTablet);
- mActionsView.updateSplitButtonDisabledFlags(FLAG_SINGLE_TASK, /*enable=*/ false);
+ // Update flags to see if actions bar should show buttons for a single task or a pair of
+ // tasks.
+ mActionsView.updateForGroupedTask(isGroupedTask);
+ // Update flags to see if split button should be hidden.
+ mActionsView.updateForTablet(mActivity.getDeviceProfile().isTablet);
+
if (isDesktopModeSupported()) {
boolean isCurrentDesktop = getCurrentPageTaskView() instanceof DesktopTaskView;
mActionsView.updateHiddenFlags(HIDDEN_DESKTOP, isCurrentDesktop);
diff --git a/quickstep/src/com/android/quickstep/views/ScreenshotActionButton.kt b/quickstep/src/com/android/quickstep/views/ScreenshotActionButton.kt
new file mode 100644
index 0000000..9cb48b8
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/ScreenshotActionButton.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.quickstep.views
+
+import android.content.Context
+import android.util.AttributeSet
+
+/** A button on the Overview Actions Bar for screenshotting the focused app. */
+class ScreenshotActionButton : ActionButton {
+ companion object {
+ const val FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT = 1 shl 0
+ }
+
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int
+ ) : super(context, attrs, defStyleAttr)
+
+ /** Show/hide the button when the focused task is a single/pair. */
+ override fun updateForMultipleTasks(hasMultipleTasks: Boolean) {
+ // Hidden for multiple tasks
+ updateHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT, hasMultipleTasks)
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/SplitActionButton.kt b/quickstep/src/com/android/quickstep/views/SplitActionButton.kt
new file mode 100644
index 0000000..88d1a77
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/SplitActionButton.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.quickstep.views
+
+import android.content.Context
+import android.util.AttributeSet
+
+/** A button on the Overview Actions Bar for initiating split screen. */
+class SplitActionButton : ActionButton {
+ companion object {
+ const val FLAG_IS_NOT_TABLET_HIDE_SPLIT = 1 shl 0
+ const val FLAG_MULTIPLE_TASKS_HIDE_SPLIT = 1 shl 1
+ }
+
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int
+ ) : super(context, attrs, defStyleAttr)
+
+ /** Show/hide the button when the focused task is a single/pair. */
+ override fun updateForMultipleTasks(hasMultipleTasks: Boolean) {
+ // Hidden for multiple tasks
+ updateHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SPLIT, hasMultipleTasks)
+ }
+
+ /** Show/hide the button depending on if the device is a tablet. */
+ override fun updateForTablet(isTablet: Boolean) {
+ // Hidden for non-tablets
+ updateHiddenFlags(FLAG_IS_NOT_TABLET_HIDE_SPLIT, !isTablet)
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
index 9a2826d..c9e536a 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
@@ -20,9 +20,10 @@
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
+import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -32,17 +33,10 @@
@Test
@TaskbarModeSwitch(mode = PERSISTENT)
- public void testHideShowTaskbar() {
- getTaskbar().hide();
- mLauncher.getLaunchedAppState().showTaskbar();
- }
-
- @Test
- @TaskbarModeSwitch(mode = PERSISTENT)
- @Ignore // b/301575789
- public void testHideTaskbarPersistsOnRecreate() {
- getTaskbar().hide();
- mLauncher.recreateTaskbar();
- mLauncher.getLaunchedAppState().assertTaskbarHidden();
+ @PortraitLandscape
+ @NavigationModeSwitch
+ public void testTaskbarFillsWidth() {
+ // Width check is performed inside TAPL whenever getTaskbar() is called.
+ getTaskbar();
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index b3cc215..0bcdb19 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
-import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
import static com.android.quickstep.TaskbarModeSwitchRule.Mode.TRANSIENT;
import static org.junit.Assert.assertEquals;
@@ -295,7 +294,8 @@
}
@Test
- @TaskbarModeSwitch(mode = PERSISTENT)
+ @TaskbarModeSwitch
+ @Ignore // b/314873201
public void testQuickSwitchToPreviousAppForTablet() throws Exception {
assumeTrue(mLauncher.isTablet());
startTestActivity(2);
@@ -304,22 +304,33 @@
// Set ignoreTaskbarVisibility to true to verify the task bar visibility explicitly.
mLauncher.setIgnoreTaskbarVisibility(true);
- // Expect task bar invisible when the launched app was the IME activity.
- LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
- if (isHardwareKeyboard()) {
- launchedAppState.assertTaskbarVisible();
- } else {
- launchedAppState.assertTaskbarHidden();
+
+ try {
+ boolean isTransientTaskbar = mLauncher.isTransientTaskbar();
+ // Expect task bar invisible when the launched app was the IME activity.
+ LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
+ if (!isTransientTaskbar && isHardwareKeyboard()) {
+ launchedAppState.assertTaskbarVisible();
+ } else {
+ launchedAppState.assertTaskbarHidden();
+ }
+
+ // Quick-switch to the test app with swiping to right.
+ quickSwitchToPreviousAppAndAssert(true /* toRight */);
+
+ assertTestActivityIsRunning(2,
+ "The first app we should have quick switched to is not running");
+ launchedAppState = getAndAssertLaunchedApp();
+ if (isTransientTaskbar) {
+ launchedAppState.assertTaskbarHidden();
+ } else {
+ // Expect taskbar visible when the launched app was the test activity.
+ launchedAppState.assertTaskbarVisible();
+ }
+ } finally {
+ // Reset ignoreTaskbarVisibility to ensure other tests still verify it.
+ mLauncher.setIgnoreTaskbarVisibility(false);
}
-
- // Quick-switch to the test app with swiping to right.
- quickSwitchToPreviousAppAndAssert(true /* toRight */);
-
- assertTestActivityIsRunning(2,
- "The first app we should have quick switched to is not running");
- // Expect task bar visible when the launched app was the test activity.
- launchedAppState = getAndAssertLaunchedApp();
- launchedAppState.assertTaskbarVisible();
}
private boolean isHardwareKeyboard() {
@@ -358,7 +369,7 @@
@Test
@PortraitLandscape
- @TaskbarModeSwitch(mode = PERSISTENT)
+ @TaskbarModeSwitch()
@PlatinumTest(focusArea = "launcher")
@TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/309820115
@ScreenRecord // b/309820115
@@ -454,6 +465,7 @@
@Test
@PortraitLandscape
+ @TaskbarModeSwitch
public void testTaskbarDeadzonesForTablet() throws Exception {
assumeTrue(mLauncher.isTablet());
@@ -466,15 +478,29 @@
launcher -> assertTrue("Should have at least 3 tasks",
getTaskCount(launcher) >= 3));
- // On persistent taskbar, it should not dismiss when tapping the taskbar
- overview.touchTaskbarBottomCorner(/* tapRight= */ false);
- assertTrue("Launcher internal state should be Overview",
- isInState(() -> LauncherState.OVERVIEW));
+ if (mLauncher.isTransientTaskbar()) {
+ // On transient taskbar, it should dismiss when tapping outside taskbar bounds.
+ overview.touchTaskbarBottomCorner(/* tapRight= */ false);
+ assertTrue("Launcher internal state should be Normal",
+ isInState(() -> LauncherState.NORMAL));
- // On persistent taskbar, it should not dismiss when tapping the taskbar
- overview.touchTaskbarBottomCorner(/* tapRight= */ true);
- assertTrue("Launcher internal state should be Overview",
- isInState(() -> LauncherState.OVERVIEW));
+ overview = mLauncher.getWorkspace().switchToOverview();
+
+ // On transient taskbar, it should dismiss when tapping outside taskbar bounds.
+ overview.touchTaskbarBottomCorner(/* tapRight= */ true);
+ assertTrue("Launcher internal state should be Normal",
+ isInState(() -> LauncherState.NORMAL));
+ } else {
+ // On persistent taskbar, it should not dismiss when tapping the taskbar
+ overview.touchTaskbarBottomCorner(/* tapRight= */ false);
+ assertTrue("Launcher internal state should be Overview",
+ isInState(() -> LauncherState.OVERVIEW));
+
+ // On persistent taskbar, it should not dismiss when tapping the taskbar
+ overview.touchTaskbarBottomCorner(/* tapRight= */ true);
+ assertTrue("Launcher internal state should be Overview",
+ isInState(() -> LauncherState.OVERVIEW));
+ }
}
@Test
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
index db23cc0..7109bbf 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
@@ -24,6 +24,7 @@
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
import org.junit.Test;
@@ -64,4 +65,12 @@
getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
mLauncher.getLaunchedAppState().clickStashedTaskbarToGoHome();
}
+
+ @Test
+ @TaskbarModeSwitch(mode = TRANSIENT)
+ @PortraitLandscape
+ public void testSwipeToStashAndUnstash() {
+ getTaskbar().swipeDownToStash();
+ mLauncher.getLaunchedAppState().swipeUpToUnstashTaskbar();
+ }
}
diff --git a/res/layout/widgets_two_pane_sheet_foldable.xml b/res/layout/widgets_two_pane_sheet_foldable.xml
new file mode 100644
index 0000000..93c0c70
--- /dev/null
+++ b/res/layout/widgets_two_pane_sheet_foldable.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="utf-8"?><!-- 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.
+-->
+<com.android.launcher3.widget.picker.WidgetsTwoPaneSheet
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:orientation="vertical"
+ android:theme="?attr/widgetsTheme">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:importantForAccessibility="no">
+
+ <View
+ android:id="@+id/collapse_handle"
+ android:gravity="center_horizontal"
+ android:layout_width="@dimen/bottom_sheet_handle_width"
+ android:layout_height="@dimen/bottom_sheet_handle_height"
+ android:layout_marginTop="@dimen/bottom_sheet_handle_margin"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ android:background="@drawable/widget_picker_collapse_handle"/>
+
+ <TextView
+ android:id="@+id/title"
+ android:gravity="center_horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="24dp"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
+ android:text="@string/widget_button_text"
+ app:layout_constraintTop_toBottomOf="@id/collapse_handle"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ android:textColor="?attr/widgetPickerTitleColor"
+ android:textSize="24sp" />
+
+ <FrameLayout
+ android:id="@+id/recycler_view_container"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintTop_toBottomOf="@id/title"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintWidth_percent="0.33"
+ app:layout_constraintWidth_min="254dp"
+ app:layout_constraintWidth_max="395dp">
+ <TextView
+ android:id="@+id/fast_scroller_popup"
+ style="@style/FastScrollerPopup"
+ android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
+
+ <!-- Fast scroller popup -->
+ <com.android.launcher3.views.RecyclerViewFastScroller
+ android:id="@+id/fast_scroller"
+ android:layout_width="@dimen/fastscroll_width"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/fastscroll_end_margin" />
+
+ <com.android.launcher3.widget.picker.WidgetsRecyclerView
+ android:id="@+id/search_widgets_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
+ android:visibility="gone" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/right_pane_container"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_marginEnd="@dimen/widget_list_horizontal_margin_two_pane"
+ android:paddingTop="@dimen/widget_list_horizontal_margin_two_pane"
+ app:layout_constraintTop_toBottomOf="@id/title"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/recycler_view_container"
+ app:layout_constraintEnd_toEndOf="parent">
+ <TextView
+ android:id="@+id/no_widgets_text"
+ style="@style/PrimaryHeadline"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:textSize="18sp"
+ android:visibility="gone"
+ tools:text="No widgets available" />
+ <ScrollView
+ android:id="@+id/right_pane_scroll_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:clipToOutline="true"
+ android:paddingBottom="36dp"
+ android:background="@drawable/widgets_surface_background"
+ android:id="@+id/right_pane">
+ <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
+ android:id="@+id/recommended_widget_table"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingHorizontal=
+ "@dimen/widget_list_horizontal_margin_two_pane"
+ android:visibility="gone" />
+ </LinearLayout>
+ </ScrollView>
+ </FrameLayout>
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</com.android.launcher3.widget.picker.WidgetsTwoPaneSheet>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 025003b..242c439 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -176,6 +176,7 @@
<dimen name="widget_tabs_horizontal_padding">16dp</dimen>
<dimen name="widget_apps_tabs_vertical_padding">6dp</dimen>
<dimen name="widget_picker_landscape_tablet_left_right_margin">117dp</dimen>
+ <dimen name="widget_picker_two_panels_left_right_margin">0dp</dimen>
<dimen name="recommended_widgets_table_vertical_padding">8dp</dimen>
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0278e4f..126efbb 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -22,7 +22,6 @@
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
import static com.android.app.animation.Interpolators.EMPHASIZED;
-import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
import static com.android.launcher3.AbstractFloatingView.TYPE_FOLDER;
import static com.android.launcher3.AbstractFloatingView.TYPE_ICON_SURFACE;
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
@@ -351,14 +350,9 @@
// UI and state for the overview panel
private View mOverviewPanel;
- @Thunk
- boolean mWorkspaceLoading = true;
-
// Used to notify when an activity launch has been deferred because launcher is not yet resumed
// TODO: See if we can remove this later
private Runnable mOnDeferredActivityLaunchCallback;
-
- private ViewOnDrawExecutor mPendingExecutor;
private OnPreDrawListener mOnInitialBindListener;
private LauncherModel mModel;
@@ -1075,7 +1069,7 @@
}
private void logStopAndResume(boolean isResume) {
- if (mPendingExecutor != null) return;
+ if (mModelCallbacks.getPendingExecutor() != null) return;
int pageIndex = mWorkspace.isOverlayShown() ? -1 : mWorkspace.getCurrentPage();
int statsLogOrdinal = mStateManager.getState().statsLogOrdinal;
@@ -1715,7 +1709,7 @@
mAppWidgetHolder.destroy();
TextKeyListener.getInstance().release();
- clearPendingBinds();
+ mModelCallbacks.clearPendingBinds();
LauncherAppState.getIDP(this).removeOnChangeListener(this);
mOverlayManager.onActivityDestroyed();
@@ -2077,48 +2071,9 @@
return mModelCallbacks.getPagesToBindSynchronously(orderedScreenIds);
}
- /**
- * Clear any pending bind callbacks. This is called when is loader is planning to
- * perform a full rebind from scratch.
- */
- @Override
- public void clearPendingBinds() {
- if (mPendingExecutor != null) {
- mPendingExecutor.cancel();
- mPendingExecutor = null;
-
- // We might have set this flag previously and forgot to clear it.
- mAppsView.getAppsStore()
- .disableDeferUpdatesSilently(AllAppsStore.DEFER_UPDATES_NEXT_DRAW);
- }
- }
-
- /**
- * Refreshes the shortcuts shown on the workspace.
- * <p>
- * Implementation of the method from LauncherModel.Callbacks.
- */
@Override
public void startBinding() {
- TraceHelper.INSTANCE.beginSection("startBinding");
- // Floating panels (except the full widget sheet) are associated with individual icons. If
- // we are starting a fresh bind, close all such panels as all the icons are about
- // to go away.
- AbstractFloatingView.closeOpenViews(this, true, TYPE_ALL & ~TYPE_REBIND_SAFE);
-
- setWorkspaceLoading(true);
-
- // Clear the workspace because it's going to be rebound
- mDragController.cancelDrag();
-
- mWorkspace.clearDropTargets();
- mWorkspace.removeAllWorkspaceScreens();
- mAppWidgetHolder.clearViews();
-
- if (mHotseat != null) {
- mHotseat.resetLayout(getDeviceProfile().isVerticalBarLayout());
- }
- TraceHelper.INSTANCE.endSection();
+ mModelCallbacks.startBinding();
}
@Override
@@ -2500,8 +2455,8 @@
}
public void clearPendingExecutor(ViewOnDrawExecutor executor) {
- if (mPendingExecutor == executor) {
- mPendingExecutor = null;
+ if (mModelCallbacks.getPendingExecutor() == executor) {
+ mModelCallbacks.setPendingExecutor(null);
}
}
@@ -2512,9 +2467,9 @@
mModelCallbacks.setSynchronouslyBoundPages(boundPages);
mModelCallbacks.setPagesToBindSynchronously(new IntSet());
- clearPendingBinds();
+ mModelCallbacks.clearPendingBinds();
ViewOnDrawExecutor executor = new ViewOnDrawExecutor(pendingTasks);
- mPendingExecutor = executor;
+ mModelCallbacks.setPendingExecutor(executor);
if (!isInState(ALL_APPS)) {
mAppsView.getAppsStore().enableDeferUpdates(AllAppsStore.DEFER_UPDATES_NEXT_DRAW);
pendingTasks.add(() -> mAppsView.getAppsStore().disableDeferUpdates(
@@ -2568,7 +2523,7 @@
TraceHelper.INSTANCE.beginSection("finishBindingItems");
mWorkspace.restoreInstanceStateForRemainingPages();
- setWorkspaceLoading(false);
+ mModelCallbacks.setWorkspaceLoading(false);
if (mPendingActivityResult != null) {
handleActivityResult(mPendingActivityResult.requestCode,
@@ -2851,7 +2806,7 @@
writer.println(prefix + "Misc:");
dumpMisc(prefix + "\t", writer);
- writer.println(prefix + "\tmWorkspaceLoading=" + mWorkspaceLoading);
+ writer.println(prefix + "\tmWorkspaceLoading=" + mModelCallbacks.getWorkspaceLoading());
writer.println(prefix + "\tmPendingRequestArgs=" + mPendingRequestArgs
+ " mPendingActivityResult=" + mPendingActivityResult);
writer.println(prefix + "\tmRotationHelper: " + mRotationHelper);
@@ -3079,21 +3034,17 @@
// Getters and Setters
- private void setWorkspaceLoading(boolean value) {
- mWorkspaceLoading = value;
- }
-
public boolean isWorkspaceLocked() {
- return mWorkspaceLoading || mPendingRequestArgs != null;
+ return isWorkspaceLoading() || mPendingRequestArgs != null;
}
public boolean isWorkspaceLoading() {
- return mWorkspaceLoading;
+ return mModelCallbacks.getWorkspaceLoading();
}
@Override
public boolean isBindingItems() {
- return mWorkspaceLoading;
+ return isWorkspaceLoading();
}
/**
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index bcd30d3..51d7690 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -2,6 +2,7 @@
import androidx.annotation.UiThread
import com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID
+import com.android.launcher3.allapps.AllAppsStore
import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget
import com.android.launcher3.model.BgDataModel
@@ -18,6 +19,8 @@
import com.android.launcher3.util.IntSet
import com.android.launcher3.util.PackageUserKey
import com.android.launcher3.util.Preconditions
+import com.android.launcher3.util.TraceHelper
+import com.android.launcher3.util.ViewOnDrawExecutor
import com.android.launcher3.widget.PendingAddWidgetInfo
import com.android.launcher3.widget.model.WidgetsListBaseEntry
import java.util.function.Predicate
@@ -27,11 +30,55 @@
var synchronouslyBoundPages = LIntSet()
var pagesToBindSynchronously = LIntSet()
- var isFirstPagePinnedItemEnabled =
+ private var isFirstPagePinnedItemEnabled =
(BuildConfig.QSB_ON_FIRST_SCREEN && !FeatureFlags.ENABLE_SMARTSPACE_REMOVAL.get())
var stringCache: StringCache? = null
+ var pendingExecutor: ViewOnDrawExecutor? = null
+
+ var workspaceLoading = true
+
+ /**
+ * Refreshes the shortcuts shown on the workspace.
+ *
+ * Implementation of the method from LauncherModel.Callbacks.
+ */
+ override fun startBinding() {
+ TraceHelper.INSTANCE.beginSection("startBinding")
+ // Floating panels (except the full widget sheet) are associated with individual icons. If
+ // we are starting a fresh bind, close all such panels as all the icons are about
+ // to go away.
+ AbstractFloatingView.closeOpenViews(
+ launcher,
+ true,
+ AbstractFloatingView.TYPE_ALL and AbstractFloatingView.TYPE_REBIND_SAFE.inv()
+ )
+ workspaceLoading = true
+
+ // Clear the workspace because it's going to be rebound
+ launcher.dragController.cancelDrag()
+ launcher.workspace.clearDropTargets()
+ launcher.workspace.removeAllWorkspaceScreens()
+ launcher.appWidgetHolder.clearViews()
+ launcher.hotseat?.resetLayout(launcher.deviceProfile.isVerticalBarLayout)
+ TraceHelper.INSTANCE.endSection()
+ }
+
+ /**
+ * Clear any pending bind callbacks. This is called when is loader is planning to perform a full
+ * rebind from scratch.
+ */
+ override fun clearPendingBinds() {
+ pendingExecutor?.cancel() ?: return
+ pendingExecutor = null
+
+ // We might have set this flag previously and forgot to clear it.
+ launcher.appsView.appsStore.disableDeferUpdatesSilently(
+ AllAppsStore.DEFER_UPDATES_NEXT_DRAW
+ )
+ }
+
override fun preAddApps() {
// If there's an undo snackbar, force it to complete to ensure empty screens are removed
// before trying to add new items.
@@ -119,7 +166,7 @@
val visibleIds =
when {
!pagesToBindSynchronously.isEmpty -> pagesToBindSynchronously
- !launcher.isWorkspaceLoading -> launcher.workspace.currentPageScreenIds
+ !workspaceLoading -> launcher.workspace.currentPageScreenIds
else -> synchronouslyBoundPages
}
// Launcher IntArray has the same name as Kotlin IntArray
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index b74699a..e0f6101 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -79,7 +79,6 @@
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
import com.android.launcher3.graphics.TintedDrawableSpan;
-import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.icons.ShortcutCachingLogic;
@@ -91,6 +90,7 @@
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.testing.shared.ResourceUtils;
+import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.util.Themes;
@@ -676,12 +676,11 @@
}
if (badge == null) {
- try (LauncherIcons li = LauncherIcons.obtain(context)) {
- badge = BitmapInfo.LOW_RES_INFO.withFlags(
- li.getBitmapFlagOp(new BaseIconFactory.IconOptions().setUser(
- UserCache.INSTANCE.get(context).getUserInfo(info.user))))
- .getBadgeDrawable(context, useTheme);
- }
+ badge = BitmapInfo.LOW_RES_INFO.withFlags(
+ UserCache.INSTANCE.get(context)
+ .getUserInfo(info.user)
+ .applyBitmapInfoFlags(FlagOp.NO_OP))
+ .getBadgeDrawable(context, useTheme);
if (badge == null) {
badge = new ColorDrawable(Color.TRANSPARENT);
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index bed6efb..746f1cf 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -270,10 +270,6 @@
public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(270391693,
"IME_STICKY_SNACKBAR_EDU", ENABLED, "Show sticky IME edu in AllApps");
- public static final BooleanFlag ENABLE_PEOPLE_TILE_PREVIEW = getDebugFlag(270391653,
- "ENABLE_PEOPLE_TILE_PREVIEW", DISABLED,
- "Experimental: Shows conversation shortcuts on home screen as search results");
-
public static final BooleanFlag FOLDER_NAME_MAJORITY_RANKING = getDebugFlag(270391638,
"FOLDER_NAME_MAJORITY_RANKING", ENABLED,
"Suggests folder names based on majority based ranking.");
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 1b1d347..2c834bd 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -47,6 +47,7 @@
import com.android.launcher3.testing.shared.HotseatCellCenterRequest;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.testing.shared.WorkspaceCellCenterRequest;
+import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.ResourceBasedOverride;
import com.android.launcher3.widget.picker.WidgetsFullSheet;
@@ -179,6 +180,11 @@
mDeviceProfile.numShownAllAppsColumns);
return response;
+ case TestProtocol.REQUEST_IS_TRANSIENT_TASKBAR:
+ response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+ DisplayController.isTransientTaskbar(mContext));
+ return response;
+
case TestProtocol.REQUEST_IS_TWO_PANELS:
response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
FOLDABLE_SINGLE_PAGE.get() ? false : mDeviceProfile.isTwoPanels);
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 4c83668..045ca79 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -71,7 +71,7 @@
private static final String TAG = "DisplayController";
private static final boolean DEBUG = false;
- private static boolean sTransientTaskbarStatusForTests;
+ private static boolean sTransientTaskbarStatusForTests = true;
// TODO(b/254119092) remove all logs with this tag
public static final String TASKBAR_NOT_DESTROYED_TAG = "b/254119092";
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index e4df413..a1cd697 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -41,6 +41,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.Utilities;
+import com.android.launcher3.testing.shared.ResourceUtils;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.TouchController;
@@ -559,7 +560,8 @@
DeviceProfile dp = mActivity.getDeviceProfile();
if (dp.isTaskbarPresent) {
// Ignore taskbar gesture insets to avoid interfering with TouchControllers.
- gestureInsetBottom = Math.max(0, gestureInsetBottom - dp.taskbarHeight);
+ gestureInsetBottom = ResourceUtils.getNavbarSize(
+ ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getResources());
}
mSystemGestureRegion.set(
Math.max(gestureInsets.left, imeInset.left),
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index cbc85b6..5cdad03 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -166,12 +166,16 @@
return show(activityContext, targetRect, items, shouldAddArrow, 0 /* width */);
}
- public static <T extends Context & ActivityContext> OptionsPopupView<T> show(
- ActivityContext activityContext,
+ @Nullable
+ private static <T extends Context & ActivityContext> OptionsPopupView<T> show(
+ @Nullable ActivityContext activityContext,
RectF targetRect,
List<OptionItem> items,
boolean shouldAddArrow,
int width) {
+ if (activityContext == null) {
+ return null;
+ }
OptionsPopupView<T> popup = (OptionsPopupView<T>) activityContext.getLayoutInflater()
.inflate(R.layout.longpress_options_menu, activityContext.getDragLayer(), false);
popup.mTargetRect = targetRect;
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 9855b20..9adc2ee 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -16,6 +16,7 @@
package com.android.launcher3.widget;
import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_TIP_SEEN;
import android.content.Context;
@@ -182,12 +183,8 @@
DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
int widthUsed;
if (deviceProfile.isTablet) {
- int margin = deviceProfile.allAppsLeftRightMargin;
- if (deviceProfile.isLandscape && !deviceProfile.isTwoPanels) {
- margin = getResources().getDimensionPixelSize(
- R.dimen.widget_picker_landscape_tablet_left_right_margin);
- }
- widthUsed = Math.max(2 * margin, 2 * (mInsets.left + mInsets.right));
+ widthUsed = Math.max(2 * getTabletMargin(deviceProfile),
+ 2 * (mInsets.left + mInsets.right));
} else if (mInsets.bottom > 0) {
widthUsed = mInsets.left + mInsets.right;
} else {
@@ -202,6 +199,18 @@
MeasureSpec.getSize(heightMeasureSpec));
}
+ private int getTabletMargin(DeviceProfile deviceProfile) {
+ if (deviceProfile.isLandscape && !deviceProfile.isTwoPanels) {
+ return getResources().getDimensionPixelSize(
+ R.dimen.widget_picker_landscape_tablet_left_right_margin);
+ }
+ if (deviceProfile.isTwoPanels && enableUnfoldedTwoPanePicker()) {
+ return getResources().getDimensionPixelSize(
+ R.dimen.widget_picker_two_panels_left_right_margin);
+ }
+ return deviceProfile.allAppsLeftRightMargin;
+ }
+
@Override
protected Interpolator getIdleInterpolator() {
return mActivityContext.getDeviceProfile().isTablet
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index da90f17..583ef1a 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -17,6 +17,7 @@
import static android.view.View.MeasureSpec.makeMeasureSpec;
+import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_DIALOG_SEEN;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
@@ -62,7 +63,6 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.UserManagerState;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.pm.UserCache;
@@ -163,9 +163,7 @@
private boolean mIsInSearchMode;
private boolean mIsNoWidgetsViewNeeded;
@Px private int mMaxSpanPerRow;
- private final DeviceProfile mDeviceProfile;
-
- private int mOrientation;
+ private DeviceProfile mDeviceProfile;
protected TextView mNoWidgetsView;
protected StickyHeaderLayout mSearchScrollView;
@@ -179,7 +177,6 @@
public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mDeviceProfile = mActivityContext.getDeviceProfile();
- mOrientation = context.getResources().getConfiguration().orientation;
mUserCache = UserCache.INSTANCE.get(context);
mHasWorkProfile = mUserCache.getUserProfiles()
.stream()
@@ -676,30 +673,31 @@
/** Shows the {@link WidgetsFullSheet} on the launcher. */
public static WidgetsFullSheet show(BaseActivity activity, boolean animate) {
- boolean isTwoPane = activity.getDeviceProfile().isTablet
- && activity.getDeviceProfile().isLandscape
- && (!activity.getDeviceProfile().isTwoPanels
- || FeatureFlags.UNFOLDED_WIDGET_PICKER.get());
-
- WidgetsFullSheet sheet;
- if (isTwoPane) {
- sheet = (WidgetsTwoPaneSheet) activity.getLayoutInflater().inflate(
- R.layout.widgets_two_pane_sheet,
- activity.getDragLayer(),
- false);
- } else {
- sheet = (WidgetsFullSheet) activity.getLayoutInflater().inflate(
- R.layout.widgets_full_sheet,
- activity.getDragLayer(),
- false);
- }
-
+ WidgetsFullSheet sheet = (WidgetsFullSheet) activity.getLayoutInflater().inflate(
+ getWidgetSheetId(activity),
+ activity.getDragLayer(),
+ false);
sheet.attachToContainer();
sheet.mIsOpen = true;
sheet.open(animate);
return sheet;
}
+ private static int getWidgetSheetId(BaseActivity activity) {
+ boolean isTwoPane = (activity.getDeviceProfile().isTablet
+ && activity.getDeviceProfile().isLandscape
+ && !activity.getDeviceProfile().isTwoPanels)
+ // Enables two pane picker for unfolded foldables if the flag is on.
+ || (activity.getDeviceProfile().isTwoPanels && enableUnfoldedTwoPanePicker());
+
+ if (isTwoPane && activity.getDeviceProfile().isTwoPanels) {
+ return R.layout.widgets_two_pane_sheet_foldable;
+ } else if (isTwoPane) {
+ return R.layout.widgets_two_pane_sheet;
+ }
+ return R.layout.widgets_full_sheet;
+ }
+
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return isTouchOnScrollbar(ev) || super.onInterceptTouchEvent(ev);
@@ -790,17 +788,25 @@
if (mIsInSearchMode) {
mSearchBar.reset();
}
+ }
- // Checks the orientation of the screen
- if (mOrientation != newConfig.orientation) {
- mOrientation = newConfig.orientation;
- if (mDeviceProfile.isTablet && !mDeviceProfile.isTwoPanels) {
- handleClose(false);
- show(BaseActivity.fromContext(getContext()), false);
- } else {
- reset();
- }
+ @Override
+ public void onDeviceProfileChanged(DeviceProfile dp) {
+ if (mDeviceProfile.isLandscape != dp.isLandscape && dp.isTablet && !dp.isTwoPanels) {
+ handleClose(false);
+ show(BaseActivity.fromContext(getContext()), false);
+ } else {
+ reset();
}
+
+ // When folding/unfolding the foldables, we need to switch between the regular widget picker
+ // and the two pane picker, so we rebuild the picker with the correct layout.
+ if (mDeviceProfile.isTwoPanels != dp.isTwoPanels && enableUnfoldedTwoPanePicker()) {
+ handleClose(false);
+ show(BaseActivity.fromContext(getContext()), false);
+ }
+
+ mDeviceProfile = dp;
}
@Override
diff --git a/tests/assets/ReorderWidgets/full_reorder_case b/tests/assets/ReorderWidgets/full_reorder_case
index 33ebaae..850e4fd 100644
--- a/tests/assets/ReorderWidgets/full_reorder_case
+++ b/tests/assets/ReorderWidgets/full_reorder_case
@@ -20,7 +20,7 @@
bbmm
iimm
iiaa
-arguments: 0 3
+arguments: 0 2
board: 4x4
xxxx
bbii
diff --git a/tests/assets/ReorderWidgets/simple_reorder_case b/tests/assets/ReorderWidgets/simple_reorder_case
index f5eb7b6..2c50ce4 100644
--- a/tests/assets/ReorderWidgets/simple_reorder_case
+++ b/tests/assets/ReorderWidgets/simple_reorder_case
@@ -34,7 +34,7 @@
--mm
--mm
----
-arguments: 3 3
+arguments: 2 2
board: 4x4
xxxx
----
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index d5a645e..e19905f 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -30,6 +30,8 @@
public static final String FOLDER_OPENED_MESSAGE = "TAPL_FOLDER_OPENED";
public static final String SEARCH_RESULT_COMPLETE = "SEARCH_RESULT_COMPLETE";
public static final String LAUNCHER_ACTIVITY_STOPPED_MESSAGE = "TAPL_LAUNCHER_ACTIVITY_STOPPED";
+ public static final String WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE =
+ "TAPL_WALLPAPER_OPEN_ANIMATION_FINISHED";
public static final int NORMAL_STATE_ORDINAL = 0;
public static final int SPRING_LOADED_STATE_ORDINAL = 1;
public static final int OVERVIEW_STATE_ORDINAL = 2;
@@ -96,8 +98,9 @@
public static final String REQUEST_DISABLE_BLOCK_TIMEOUT = "disable-block-timeout";
public static final String REQUEST_ENABLE_TRANSIENT_TASKBAR = "enable-transient-taskbar";
public static final String REQUEST_DISABLE_TRANSIENT_TASKBAR = "disable-transient-taskbar";
+ public static final String REQUEST_IS_TRANSIENT_TASKBAR = "is-transient-taskbar";
public static final String REQUEST_UNSTASH_TASKBAR_IF_STASHED = "unstash-taskbar-if-stashed";
- public static final String REQUEST_STASHED_TASKBAR_HEIGHT = "stashed-taskbar-height";
+ public static final String REQUEST_TASKBAR_FROM_NAV_THRESHOLD = "taskbar-from-nav-threshold";
public static final String REQUEST_STASHED_TASKBAR_SCALE = "taskbar-stash-handle-scale";
public static final String REQUEST_RECREATE_TASKBAR = "recreate-taskbar";
public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags";
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index b2ce400..9fdd21a 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -82,7 +82,6 @@
runTest(false);
}
-
/**
* @param acceptConfig accept the config activity
*/
@@ -101,7 +100,7 @@
// Verify that the widget id is valid and bound
assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
- setResult(acceptConfig);
+ setResultAndWaitForAnimation(acceptConfig);
if (acceptConfig) {
Wait.atMost("", new WidgetSearchCondition(), DEFAULT_ACTIVITY_TIMEOUT, mLauncher);
assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
@@ -112,12 +111,22 @@
}
}
- private void setResult(boolean success) {
+ private static void setResult(boolean success) {
getInstrumentation().getTargetContext().sendBroadcast(
WidgetConfigActivity.getCommandIntent(WidgetConfigActivity.class,
success ? "clickOK" : "clickCancel"));
}
+ private void setResultAndWaitForAnimation(boolean success) {
+ if (mLauncher.isLauncher3()) {
+ setResult(success);
+ } else {
+ mLauncher.executeAndWaitForWallpaperAnimation(
+ () -> setResult(success),
+ "setting widget coinfig result");
+ }
+ }
+
/**
* Condition for searching widget id
*/
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 7d25121..0e78565 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -54,6 +54,7 @@
private static final int MAX_SCROLL_ATTEMPTS = 40;
private static final String BOTTOM_SHEET_RES_ID = "bottom_sheet_background";
+ private static final String FAST_SCROLLER_RES_ID = "fast_scroller";
private static final Pattern EVENT_ALT_ESC_DOWN = Pattern.compile(
"Key event: KeyEvent.*?action=ACTION_DOWN.*?keyCode=KEYCODE_ESCAPE.*?metaState=0");
@@ -369,9 +370,12 @@
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to tap outside AllApps bottom sheet on the "
+ (tapRight ? "right" : "left"))) {
- final UiObject2 allAppsBottomSheet =
+
+ final UiObject2 container = (tapRight)
+ ? mLauncher.waitForLauncherObject(FAST_SCROLLER_RES_ID) :
mLauncher.waitForLauncherObject(BOTTOM_SHEET_RES_ID);
- mLauncher.touchOutsideContainer(allAppsBottomSheet, tapRight);
+
+ mLauncher.touchOutsideContainer(container, tapRight, false);
try (LauncherInstrumentation.Closable tapped = mLauncher.addContextLayer(
"tapped outside AllApps bottom sheet")) {
verifyVisibleContainerOnDismiss();
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 44869be..b6b4a47 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -186,7 +186,14 @@
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
Taskbar taskbar = new Taskbar(mLauncher);
taskbar.touchBottomCorner(tapRight);
- verifyActiveContainer();
+ if (mLauncher.isTransientTaskbar()) {
+ // Tapping outside Transient Taskbar returns to Workspace, wait for that state.
+ new Workspace(mLauncher);
+ } else {
+ // Should stay in Overview.
+ verifyActiveContainer();
+ verifyActionsViewVisibility();
+ }
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index efeb5f6..6d58a35 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -20,12 +20,11 @@
import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID;
import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_BLOCK_TIMEOUT;
-import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_BLOCK_TIMEOUT;
-import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_SHELL_DRAG_READY;
-import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_HEIGHT;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_SCALE;
+import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_TASKBAR_FROM_NAV_THRESHOLD;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
import android.graphics.Point;
import android.graphics.Rect;
@@ -84,8 +83,6 @@
public Taskbar getTaskbar() {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to get the taskbar")) {
- mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
-
return new Taskbar(mLauncher);
}
}
@@ -113,37 +110,32 @@
/**
* Returns the Taskbar in a visible state.
*
- * The taskbar must already be hidden when calling this method.
+ * The taskbar must already be hidden and in transient mode when calling this method.
*/
- public Taskbar showTaskbar() {
- mLauncher.getTestInfo(REQUEST_ENABLE_MANUAL_TASKBAR_STASHING);
+ public Taskbar swipeUpToUnstashTaskbar() {
+ mLauncher.assertTrue("Taskbar is not transient, swipe up not supported",
+ mLauncher.isTransientTaskbar());
+
mLauncher.getTestInfo(REQUEST_ENABLE_BLOCK_TIMEOUT);
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
- "want to show the taskbar")) {
+ "want to swipe up to unstash the taskbar")) {
mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
- final long downTime = SystemClock.uptimeMillis();
- final int unstashTargetY = mLauncher.getRealDisplaySize().y
- - (mLauncher.getTestInfo(REQUEST_STASHED_TASKBAR_HEIGHT)
- .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD) / 2);
- final Point unstashTarget = new Point(
- mLauncher.getRealDisplaySize().x / 2, unstashTargetY);
+ int taskbarFromNavThreshold = mLauncher.getTestInfo(REQUEST_TASKBAR_FROM_NAV_THRESHOLD)
+ .getInt(TEST_INFO_RESPONSE_FIELD);
+ int startX = mLauncher.getRealDisplaySize().x / 2;
+ int startY = mLauncher.getRealDisplaySize().y - 1;
+ int endX = startX;
+ int endY = startY - taskbarFromNavThreshold;
- mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, unstashTarget,
+ mLauncher.linearGesture(startX, startY, endX, endY, 10, /* slowDown= */ true,
LauncherInstrumentation.GestureScope.EXPECT_PILFER);
- LauncherInstrumentation.log("showTaskbar: sent down");
+ LauncherInstrumentation.log("swipeUpToUnstashTaskbar: sent linear swipe up gesture");
- try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) {
- mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
- mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, unstashTarget,
- LauncherInstrumentation.GestureScope.EXPECT_PILFER);
-
- return new Taskbar(mLauncher);
- }
+ return new Taskbar(mLauncher);
} finally {
- mLauncher.getTestInfo(REQUEST_DISABLE_MANUAL_TASKBAR_STASHING);
mLauncher.getTestInfo(REQUEST_DISABLE_BLOCK_TIMEOUT);
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index fb81700..cbf1952 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -824,12 +824,7 @@
waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
-
- if (is3PLauncher() && isTablet()) {
- waitForSystemLauncherObject(TASKBAR_RES_ID);
- } else {
- waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
- }
+ waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
return waitForLauncherObject(WORKSPACE_RES_ID);
}
@@ -839,12 +834,7 @@
waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
-
- if (is3PLauncher() && isTablet()) {
- waitForSystemLauncherObject(TASKBAR_RES_ID);
- } else {
- waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
- }
+ waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
return waitForLauncherObject(WIDGETS_RES_ID);
}
@@ -865,7 +855,7 @@
waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
- if (is3PLauncher() && isTablet()) {
+ if (is3PLauncher() && isTablet() && !isTransientTaskbar()) {
waitForSystemLauncherObject(TASKBAR_RES_ID);
} else {
waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
@@ -878,7 +868,7 @@
waitUntilLauncherObjectGone(APPS_RES_ID);
waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
- if (isTablet()) {
+ if (isTablet() && !is3PLauncher()) {
waitForSystemLauncherObject(TASKBAR_RES_ID);
} else {
waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
@@ -915,7 +905,11 @@
}
if (isTablet()) {
- waitForSystemLauncherObject(TASKBAR_RES_ID);
+ // Only check that Persistent Taskbar is visible, since Transient Taskbar
+ // may or may not be visible by design.
+ if (!isTransientTaskbar()) {
+ waitForSystemLauncherObject(TASKBAR_RES_ID);
+ }
} else {
waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
}
@@ -995,7 +989,7 @@
/**
* Using swiping up gesture to dismiss closable floating views, such as Menu or Folder Content.
*/
- private void swipeUpToCloseFloatingView(boolean gestureStartFromLauncher) {
+ private void swipeUpToCloseFloatingView() {
final Point displaySize = getRealDisplaySize();
final Optional<String> floatingRes = getFloatingResId();
@@ -1004,16 +998,11 @@
return;
}
- GestureScope gestureScope = gestureStartFromLauncher
- // Without the navigation bar layer, the gesture scope on tablets remains inside the
- // launcher process.
- ? (isTablet() ? GestureScope.DONT_EXPECT_PILFER : GestureScope.EXPECT_PILFER)
- : GestureScope.EXPECT_PILFER;
linearGesture(
displaySize.x / 2, displaySize.y - 1,
displaySize.x / 2, 0,
ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
- false, gestureScope);
+ false, GestureScope.EXPECT_PILFER);
try (LauncherInstrumentation.Closable c1 = addContextLayer(
String.format("Swiped up from floating view %s to home", floatingRes.get()))) {
@@ -1081,11 +1070,8 @@
final Point displaySize = getRealDisplaySize();
- boolean gestureStartFromLauncher =
- isTablet() ? !isLauncher3() : isLauncherVisible();
-
// CLose floating views before going back to home.
- swipeUpToCloseFloatingView(gestureStartFromLauncher);
+ swipeUpToCloseFloatingView();
if (hasLauncherObject(WORKSPACE_RES_ID)) {
log(action = "already at home");
@@ -2039,6 +2025,7 @@
}
}
+ /** Returns the bounds of the display as a Point where x is width and y is height. */
Point getRealDisplaySize() {
final Rect displayBounds = getContext().getSystemService(WindowManager.class)
.getMaximumWindowMetrics()
@@ -2101,6 +2088,11 @@
: TestProtocol.REQUEST_DISABLE_BLOCK_TIMEOUT);
}
+ public boolean isTransientTaskbar() {
+ return getTestInfo(TestProtocol.REQUEST_IS_TRANSIENT_TASKBAR)
+ .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ }
+
/** Enables transient taskbar for testing purposes only. */
public void enableTransientTaskbar(boolean enable) {
getTestInfo(enable
@@ -2188,7 +2180,8 @@
};
}
- boolean isLauncher3() {
+ /** Returns whether the Launcher is a Launcher3 one */
+ public boolean isLauncher3() {
if (mIsLauncher3 == null) {
mIsLauncher3 = "com.android.launcher3".equals(getLauncherPackageName());
}
@@ -2313,4 +2306,14 @@
}
return result;
}
+
+ /** Executes a runnable and waits for the wallpaper-open animation completion. */
+ public void executeAndWaitForWallpaperAnimation(Runnable r, String actionName) {
+ executeAndWaitForLauncherEvent(
+ () -> r.run(),
+ event -> TestProtocol.WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE
+ .equals(event.getClassName().toString()),
+ () -> "Didn't detect finishing wallpaper-open animation",
+ actionName);
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
index 38cc321..4a0131b 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
@@ -20,6 +20,8 @@
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.UiObject2;
+import com.android.launcher3.testing.shared.TestProtocol;
+
/** Represents the menu of an overview task. */
public class OverviewTaskMenu {
@@ -59,8 +61,13 @@
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"before tapping the app info menu item")) {
- mLauncher.clickLauncherObject(
- mLauncher.findObjectInContainer(mMenu, By.text("App info")));
+ mLauncher.executeAndWaitForLauncherEvent(
+ () -> mLauncher.clickLauncherObject(
+ mLauncher.findObjectInContainer(mMenu, By.text("App info"))),
+ event -> TestProtocol.LAUNCHER_ACTIVITY_STOPPED_MESSAGE
+ .equals(event.getClassName().toString()),
+ () -> "Launcher activity didn't stop",
+ "tapped app info menu item");
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"tapped app info menu item")) {
diff --git a/tests/tapl/com/android/launcher3/tapl/Taskbar.java b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
index da26694..a202c53 100644
--- a/tests/tapl/com/android/launcher3/tapl/Taskbar.java
+++ b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
@@ -18,8 +18,6 @@
import static android.view.KeyEvent.KEYCODE_META_RIGHT;
import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID;
-import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING;
-import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING;
import android.graphics.Point;
import android.graphics.Rect;
@@ -33,6 +31,8 @@
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.UiObject2;
+import org.junit.Assert;
+
import java.util.List;
import java.util.stream.Collectors;
@@ -45,6 +45,15 @@
Taskbar(LauncherInstrumentation launcher) {
mLauncher = launcher;
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "expect new taskbar to be visible")) {
+ mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
+ }
+
+ if (!mLauncher.isTransientTaskbar()) {
+ Assert.assertEquals("Persistent taskbar should fill screen width",
+ getVisibleBounds().width(), mLauncher.getRealDisplaySize().x);
+ }
}
/**
@@ -61,33 +70,32 @@
}
/**
- * Hides this taskbar.
- *
- * The taskbar must already be visible when calling this method.
+ * Stashes this taskbar.
+ * <p>
+ * The taskbar must already be unstashed and in transient mode when calling this method.
*/
- public void hide() {
- mLauncher.getTestInfo(REQUEST_ENABLE_MANUAL_TASKBAR_STASHING);
+ public void swipeDownToStash() {
+ mLauncher.assertTrue("Taskbar is not transient, swipe down not supported",
+ mLauncher.isTransientTaskbar());
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to hide the taskbar");
LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
- final long downTime = SystemClock.uptimeMillis();
- Point stashTarget = new Point(
- mLauncher.getRealDisplaySize().x - 1, mLauncher.getRealDisplaySize().y - 1);
+ Rect taskbarBounds = getVisibleBounds();
+ int startX = taskbarBounds.centerX();
+ int startY = taskbarBounds.centerY();
+ int endX = startX;
+ int endY = mLauncher.getRealDisplaySize().y - 1;
- mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, stashTarget,
+ mLauncher.linearGesture(startX, startY, endX, endY, 10, false,
LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
- LauncherInstrumentation.log("hideTaskbar: sent down");
-
- try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) {
+ LauncherInstrumentation.log("swipeDownToStash: sent linear swipe down gesture");
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+ "expect transient taskbar to be hidden after swipe down")) {
mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
- mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, stashTarget,
- LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
}
- } finally {
- mLauncher.getTestInfo(REQUEST_DISABLE_MANUAL_TASKBAR_STASHING);
}
}