Merge "Make multi-instances split opt-in based" into tm-qpr-dev
diff --git a/quickstep/res/layout-sw600dp-land/allset_navigation_and_hint.xml b/quickstep/res/layout-sw600dp-land/allset_navigation_and_hint.xml
deleted file mode 100644
index 3bfa6da..0000000
--- a/quickstep/res/layout-sw600dp-land/allset_navigation_and_hint.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 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.
--->
-<merge xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
-
- <TextView
- android:id="@+id/navigation_settings"
- style="@style/TextAppearance.GestureTutorial.LinkText"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="32dp"
- android:background="?android:attr/selectableItemBackground"
- android:minHeight="48dp"
- android:text="@string/allset_navigation_settings"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/subtitle" />
-
- <TextView
- android:id="@+id/hint"
- style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/allset_page_margin_bottom"
- android:text="@string/allset_hint"
- android:textSize="@dimen/allset_page_swipe_up_text_size"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent" />
-
-</merge>
\ No newline at end of file
diff --git a/quickstep/res/layout-sw600dp/allset_navigation_and_hint.xml b/quickstep/res/layout-sw600dp/allset_navigation_and_hint.xml
index 9559072..44b3ecb 100644
--- a/quickstep/res/layout-sw600dp/allset_navigation_and_hint.xml
+++ b/quickstep/res/layout-sw600dp/allset_navigation_and_hint.xml
@@ -21,12 +21,11 @@
style="@style/TextAppearance.GestureTutorial.LinkText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="96dp"
+ android:layout_marginTop="24dp"
android:background="?android:attr/selectableItemBackground"
android:minHeight="48dp"
android:text="@string/allset_navigation_settings"
- app:layout_constraintBottom_toTopOf="@id/hint"
- app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/subtitle"
app:layout_constraintStart_toStartOf="parent" />
<TextView
@@ -34,7 +33,7 @@
style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/allset_page_margin_bottom"
+ android:layout_marginBottom="24dp"
android:text="@string/allset_hint"
android:textSize="@dimen/allset_page_swipe_up_text_size"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/values-sw600dp-land/dimens.xml b/quickstep/res/values-sw600dp-land/dimens.xml
index 5507fcf..dc10c24 100644
--- a/quickstep/res/values-sw600dp-land/dimens.xml
+++ b/quickstep/res/values-sw600dp-land/dimens.xml
@@ -20,6 +20,5 @@
<!-- All Set page -->
<dimen name="allset_page_margin_horizontal">48dp</dimen>
- <dimen name="allset_page_margin_bottom">24dp</dimen>
</resources>
diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml
index c96ad11..5899814 100644
--- a/quickstep/res/values-sw600dp/dimens.xml
+++ b/quickstep/res/values-sw600dp/dimens.xml
@@ -36,7 +36,6 @@
<!-- All Set page -->
<dimen name="allset_page_margin_horizontal">120dp</dimen>
- <dimen name="allset_page_margin_bottom">24dp</dimen>
<dimen name="allset_page_allset_text_size">38sp</dimen>
<dimen name="allset_page_swipe_up_text_size">15sp</dimen>
diff --git a/quickstep/res/values-sw720dp-land/dimens.xml b/quickstep/res/values-sw720dp-land/dimens.xml
index 4bc8bf3..02d1189 100644
--- a/quickstep/res/values-sw720dp-land/dimens.xml
+++ b/quickstep/res/values-sw720dp-land/dimens.xml
@@ -17,7 +17,4 @@
<resources>
<!-- Overview actions -->
<dimen name="overview_actions_top_margin">20dp</dimen>
-
- <!-- All Set page-->
- <dimen name="allset_page_margin_bottom">24dp</dimen>
</resources>
diff --git a/quickstep/res/values-sw720dp/dimens.xml b/quickstep/res/values-sw720dp/dimens.xml
index a84b939..585f01e 100644
--- a/quickstep/res/values-sw720dp/dimens.xml
+++ b/quickstep/res/values-sw720dp/dimens.xml
@@ -35,7 +35,6 @@
<dimen name="overview_grid_side_margin">64dp</dimen>
<!-- All Set page-->
- <dimen name="allset_page_margin_bottom">0dp</dimen>
<dimen name="allset_page_allset_text_size">42sp</dimen>
<dimen name="allset_page_swipe_up_text_size">16sp</dimen>
</resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 6e3fd32..cd60879 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -202,7 +202,6 @@
<!-- All Set page -->
<dimen name="allset_page_margin_horizontal">40dp</dimen>
- <dimen name="allset_page_margin_bottom">0dp</dimen>
<dimen name="allset_page_allset_text_size">36sp</dimen>
<dimen name="allset_page_swipe_up_text_size">14sp</dimen>
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 868d38b..4f0fdf1 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -152,6 +152,8 @@
<item name="android:background">@drawable/bg_overview_clear_all_button</item>
<item name="android:minWidth">96dp</item>
<item name="android:minHeight">48dp</item>
+ <item name="android:paddingStart">12dp</item>
+ <item name="android:paddingEnd">12dp</item>
<item name="android:stateListAnimator">@null</item>
</style>
diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
index f1e6747..df867cb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -21,6 +21,7 @@
import android.animation.Animator;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StateManager;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.fallback.RecentsState;
@@ -40,8 +41,7 @@
animateToRecentsState(toState);
// Handle tapping on live tile.
- RecentsView recentsView = mRecentsActivity.getOverviewPanel();
- recentsView.setTaskLaunchListener(toState == RecentsState.DEFAULT
+ getRecentsView().setTaskLaunchListener(toState == RecentsState.DEFAULT
? (() -> animateToRecentsState(RecentsState.BACKGROUND_APP)) : null);
}
};
@@ -70,12 +70,14 @@
* Currently this animation just force stashes the taskbar in Overview.
*/
public Animator createAnimToRecentsState(RecentsState toState, long duration) {
- boolean forceStashed = toState.hasOverviewActions();
+ boolean useStashedLauncherState = toState.hasOverviewActions();
+ boolean stashedLauncherState =
+ useStashedLauncherState && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get();
TaskbarStashController controller = mControllers.taskbarStashController;
// Set both FLAG_IN_STASHED_LAUNCHER_STATE and FLAG_IN_APP to ensure the state is respected.
// For all other states, just use the current stashed-in-app setting (e.g. if long clicked).
- controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, forceStashed);
- controller.updateStateForFlag(FLAG_IN_APP, !forceStashed);
+ controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, stashedLauncherState);
+ controller.updateStateForFlag(FLAG_IN_APP, !useStashedLauncherState);
return controller.applyStateWithoutStart(duration);
}
@@ -85,4 +87,9 @@
anim.start();
}
}
+
+ @Override
+ public RecentsView getRecentsView() {
+ return mRecentsActivity.getOverviewPanel();
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 89f0f98..beab56c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -47,6 +47,7 @@
import com.android.launcher3.util.OnboardingPrefs;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.RecentsAnimationCallbacks;
+import com.android.quickstep.views.RecentsView;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -192,7 +193,15 @@
*/
public Animator createAnimToLauncher(@NonNull LauncherState toState,
@NonNull RecentsAnimationCallbacks callbacks, long duration) {
- return mTaskbarLauncherStateController.createAnimToLauncher(toState, callbacks, duration);
+ AnimatorSet set = new AnimatorSet();
+ Animator taskbarState = mTaskbarLauncherStateController
+ .createAnimToLauncher(toState, callbacks, duration);
+ long halfDuration = Math.round(duration * 0.5f);
+ Animator translation =
+ mControllers.taskbarTranslationController.createAnimToLauncher(halfDuration);
+
+ set.playTogether(taskbarState, translation);
+ return set;
}
public boolean isDraggingItem() {
@@ -383,4 +392,9 @@
mTaskbarLauncherStateController.dumpLogs(prefix + "\t", pw);
}
+
+ @Override
+ public RecentsView getRecentsView() {
+ return mLauncher.getOverviewPanel();
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 12dbcb3..45d5739 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -30,6 +30,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.RevealOutlineAnimation;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
+import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
@@ -66,6 +67,7 @@
// Initialized in init.
private TaskbarControllers mControllers;
+ private int mTaskbarSize;
// The bounds we want to clip to in the settled state when showing the stashed handle.
private final Rect mStashedHandleBounds = new Rect();
@@ -96,15 +98,18 @@
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
Resources resources = mActivity.getResources();
if (isPhoneGestureNavMode(mActivity.getDeviceProfile())) {
- mStashedHandleView.getLayoutParams().height =
- resources.getDimensionPixelSize(R.dimen.taskbar_size);
+ mTaskbarSize = resources.getDimensionPixelSize(R.dimen.taskbar_size);
mStashedHandleWidth =
resources.getDimensionPixelSize(R.dimen.taskbar_stashed_small_screen);
} else {
- mStashedHandleView.getLayoutParams().height = deviceProfile.taskbarSize;
+ mTaskbarSize = deviceProfile.taskbarSize;
mStashedHandleWidth = resources
.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width);
}
+ int taskbarBottomMargin = DisplayController.isTransientTaskbar(mActivity)
+ ? resources.getDimensionPixelSize(R.dimen.transient_taskbar_margin)
+ : 0;
+ mStashedHandleView.getLayoutParams().height = mTaskbarSize + taskbarBottomMargin;
mTaskbarStashedHandleAlpha.get(ALPHA_INDEX_STASHED).setValue(
isPhoneGestureNavMode(deviceProfile) ? 1 : 0);
@@ -181,9 +186,17 @@
* morphs into the size of where the taskbar icons will be.
*/
public Animator createRevealAnimToIsStashed(boolean isStashed) {
+ Rect visualBounds = new Rect(mControllers.taskbarViewController.getIconLayoutBounds());
+
+ if (DisplayController.isTransientTaskbar(mActivity)) {
+ // Account for the full visual height of the transient taskbar.
+ int heightDiff = (mTaskbarSize - visualBounds.height()) / 2;
+ visualBounds.top -= heightDiff;
+ visualBounds.bottom += heightDiff;
+ }
+
final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider(
- mStashedHandleRadius, mStashedHandleRadius,
- mControllers.taskbarViewController.getIconLayoutBounds(), mStashedHandleBounds);
+ mStashedHandleRadius, mStashedHandleRadius, visualBounds, mStashedHandleBounds);
boolean isReversed = !isStashed;
boolean changingDirection = mWasLastRevealAnimReversed != isReversed;
@@ -220,6 +233,13 @@
}
/**
+ * Sets the translation of the stashed handle during the swipe up gesture.
+ */
+ protected void setTranslationYForSwipe(float transY) {
+ mStashedHandleView.setTranslationY(transY);
+ }
+
+ /**
* Should be called when the home button is disabled, so we can hide this handle as well.
*/
public void setIsHomeButtonDisabled(boolean homeDisabled) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index fad9ff4..9175226 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -78,6 +78,7 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.AutohideSuspendFlag;
+import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback;
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
import com.android.launcher3.testing.TestLogging;
@@ -90,6 +91,7 @@
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.util.ViewCache;
import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.rotation.RotationButtonController;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -132,6 +134,7 @@
private final boolean mIsUserSetupComplete;
private final boolean mIsNavBarForceVisible;
private final boolean mIsNavBarKidsMode;
+
private boolean mIsDestroyed = false;
// The flag to know if the window is excluded from magnification region computation.
private boolean mIsExcludeFromMagnificationRegion = false;
@@ -223,6 +226,7 @@
new TaskbarAllAppsController(),
new TaskbarInsetsController(this),
new VoiceInteractionWindowController(this),
+ new TaskbarTranslationController(this),
isDesktopMode
? new DesktopTaskbarRecentAppsController(this)
: TaskbarRecentAppsController.DEFAULT);
@@ -755,42 +759,63 @@
if (info.isDisabled()) {
ItemClickHandler.handleDisabledItemClicked(info, this);
} else {
- Intent intent = new Intent(info.getIntent())
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- if (mIsSafeModeEnabled && !PackageManagerHelper.isSystemApp(this, intent)) {
- Toast.makeText(this, R.string.safemode_shortcut_error,
- Toast.LENGTH_SHORT).show();
- } else if (info.isPromise()) {
- TestLogging.recordEvent(
- TestProtocol.SEQUENCE_MAIN, "start: taskbarPromiseIcon");
- intent = new PackageManagerHelper(this)
- .getMarketIntent(info.getTargetPackage())
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
+ TaskbarUIController taskbarUIController = mControllers.uiController;
+ RecentsView recents = taskbarUIController.getRecentsView();
+ if (recents != null
+ && taskbarUIController.getRecentsView().isSplitSelectionActive()) {
+ // If we are selecting a second app for split, launch the split tasks
+ taskbarUIController.triggerSecondAppForSplit(info, info.intent, view);
+ } else {
+ // Else launch the selected task
+ Intent intent = new Intent(info.getIntent())
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ if (mIsSafeModeEnabled && !PackageManagerHelper.isSystemApp(this, intent)) {
+ Toast.makeText(this, R.string.safemode_shortcut_error,
+ Toast.LENGTH_SHORT).show();
+ } else if (info.isPromise()) {
+ TestLogging.recordEvent(
+ TestProtocol.SEQUENCE_MAIN, "start: taskbarPromiseIcon");
+ intent = new PackageManagerHelper(this)
+ .getMarketIntent(info.getTargetPackage())
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
- } else if (info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- TestLogging.recordEvent(
- TestProtocol.SEQUENCE_MAIN, "start: taskbarDeepShortcut");
- String id = info.getDeepShortcutId();
- String packageName = intent.getPackage();
- getSystemService(LauncherApps.class)
- .startShortcut(packageName, id, null, null, info.user);
- } else {
- startItemInfoActivity(info);
+ } else if (info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ TestLogging.recordEvent(
+ TestProtocol.SEQUENCE_MAIN, "start: taskbarDeepShortcut");
+ String id = info.getDeepShortcutId();
+ String packageName = intent.getPackage();
+ getSystemService(LauncherApps.class)
+ .startShortcut(packageName, id, null, null, info.user);
+ } else {
+ startItemInfoActivity(info);
+ }
+
+ mControllers.uiController.onTaskbarIconLaunched(info);
+ } catch (NullPointerException
+ | ActivityNotFoundException
+ | SecurityException e) {
+ Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT)
+ .show();
+ Log.e(TAG, "Unable to launch. tag=" + info + " intent=" + intent, e);
}
-
- mControllers.uiController.onTaskbarIconLaunched(info);
- mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
- } catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
- Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT)
- .show();
- Log.e(TAG, "Unable to launch. tag=" + info + " intent=" + intent, e);
}
+ mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
}
} else if (tag instanceof AppInfo) {
- startItemInfoActivity((AppInfo) tag);
- mControllers.uiController.onTaskbarIconLaunched((AppInfo) tag);
+ AppInfo info = (AppInfo) tag;
+ TaskbarUIController taskbarUIController = mControllers.uiController;
+ RecentsView recents = taskbarUIController.getRecentsView();
+ if (recents != null
+ && taskbarUIController.getRecentsView().isSplitSelectionActive()) {
+ // If we are selecting a second app for split, launch the split tasks
+ taskbarUIController.triggerSecondAppForSplit(info, info.intent, view);
+ } else {
+ // Else launch the selected task
+ startItemInfoActivity((AppInfo) tag);
+ mControllers.uiController.onTaskbarIconLaunched((AppInfo) tag);
+ }
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
} else {
Log.e(TAG, "Unknown type clicked: " + tag);
@@ -834,6 +859,20 @@
}
/**
+ * Called to start the taskbar translation spring to its settled translation (0).
+ */
+ public void startTranslationSpring() {
+ mControllers.taskbarTranslationController.startSpring();
+ }
+
+ /**
+ * Returns a callback to help monitor the swipe gesture.
+ */
+ public TransitionCallback getTranslationCallbacks() {
+ return mControllers.taskbarTranslationController.getTransitionCallback();
+ }
+
+ /**
* Called when a transient Autohide flag suspend status changes.
*/
public void onTransientAutohideSuspendFlagChanged(boolean isSuspended) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index a948fb3..ff7e8e9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -34,6 +34,7 @@
val paint: Paint = Paint()
var backgroundHeight = context.deviceProfile.taskbarSize.toFloat()
+ var translationYForSwipe = 0f
private var maxBackgroundHeight = context.deviceProfile.taskbarSize.toFloat()
private val transientBackgroundBounds = context.transientTaskbarBounds
@@ -114,11 +115,13 @@
canvas.translate(canvas.width - rightCornerRadius, -rightCornerRadius)
canvas.drawPath(invertedRightCornerPath, paint)
} else {
+ // Approximates the stash/unstash animation to transform the background.
val scaleFactor = backgroundHeight / maxBackgroundHeight
val width = transientBackgroundBounds.width()
val widthScale = mapToRange(scaleFactor, 0f, 1f, 0.4f, 1f, Interpolators.LINEAR)
val newWidth = widthScale * width
val delta = width - newWidth
+ canvas.translate(0f, bottomMargin * ((1f - scaleFactor) / 2f))
// Draw shadow.
val shadowAlpha = mapToRange(paint.alpha.toFloat(), 0f, 255f, 0f, 25f,
@@ -132,9 +135,9 @@
canvas.drawRoundRect(
transientBackgroundBounds.left + (delta / 2f),
- 0f,
+ translationYForSwipe,
transientBackgroundBounds.right - (delta / 2f),
- backgroundHeight,
+ backgroundHeight + translationYForSwipe,
radius, radius, paint
)
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 12e6ba4..0328df9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -56,6 +56,7 @@
public final TaskbarInsetsController taskbarInsetsController;
public final VoiceInteractionWindowController voiceInteractionWindowController;
public final TaskbarRecentAppsController taskbarRecentAppsController;
+ public final TaskbarTranslationController taskbarTranslationController;
public final TaskbarOverlayController taskbarOverlayController;
@Nullable private LoggableTaskbarController[] mControllersToLog = null;
@@ -92,6 +93,7 @@
TaskbarAllAppsController taskbarAllAppsController,
TaskbarInsetsController taskbarInsetsController,
VoiceInteractionWindowController voiceInteractionWindowController,
+ TaskbarTranslationController taskbarTranslationController,
TaskbarRecentAppsController taskbarRecentAppsController) {
this.taskbarActivityContext = taskbarActivityContext;
this.taskbarDragController = taskbarDragController;
@@ -113,6 +115,7 @@
this.taskbarAllAppsController = taskbarAllAppsController;
this.taskbarInsetsController = taskbarInsetsController;
this.voiceInteractionWindowController = voiceInteractionWindowController;
+ this.taskbarTranslationController = taskbarTranslationController;
this.taskbarRecentAppsController = taskbarRecentAppsController;
}
@@ -144,6 +147,7 @@
taskbarInsetsController.init(this);
voiceInteractionWindowController.init(this);
taskbarRecentAppsController.init(this);
+ taskbarTranslationController.init(this);
mControllersToLog = new LoggableTaskbarController[] {
taskbarDragController, navButtonController, navbarButtonsViewController,
@@ -151,7 +155,7 @@
taskbarUnfoldAnimationController, taskbarKeyguardController,
stashedHandleViewController, taskbarStashController, taskbarEduController,
taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController,
- voiceInteractionWindowController
+ voiceInteractionWindowController, taskbarTranslationController
};
mBackgroundRendererControllers = new BackgroundRendererController[] {
taskbarDragLayerController, taskbarScrimViewController,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index 2aa4687..d0059f7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -175,6 +175,14 @@
invalidate();
}
+ /*
+ * Sets the translation of the background during the swipe up gesture.
+ */
+ protected void setBackgroundTranslationYForSwipe(float translationY) {
+ mBackgroundRenderer.setTranslationYForSwipe(translationY);
+ invalidate();
+ }
+
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 3834ba7..e54fc00 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -150,6 +150,13 @@
updateNavBarDarkIntensityMultiplier();
}
+ /**
+ * Sets the translation of the background during the swipe up gesture.
+ */
+ public void setTranslationYForSwipe(float transY) {
+ mTaskbarDragLayer.setBackgroundTranslationYForSwipe(transY);
+ }
+
private void updateBackgroundOffset() {
mTaskbarDragLayer.setTaskbarBackgroundOffset(mBgOffset.value);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
new file mode 100644
index 0000000..1a7ec13
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2022 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.taskbar;
+
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
+import static com.android.quickstep.AnimatedFloat.VALUE;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+
+import androidx.annotation.Nullable;
+import androidx.dynamicanimation.animation.SpringForce;
+
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.SpringAnimationBuilder;
+import com.android.launcher3.util.DisplayController;
+import com.android.quickstep.AnimatedFloat;
+
+import java.io.PrintWriter;
+
+/**
+ * Class responsible for translating the transient taskbar UI during a swipe gesture.
+ *
+ * The translation is controlled, in priority order:
+ * - animation to home
+ * - a spring animation
+ * - controlled by user
+ *
+ * The spring animation will play start once the user lets go or when user pauses to go to overview.
+ * When the user goes home, the stash animation will play.
+ */
+public class TaskbarTranslationController implements TaskbarControllers.LoggableTaskbarController {
+
+ private final TaskbarActivityContext mContext;
+ private TaskbarControllers mControllers;
+ private final AnimatedFloat mTranslationYForSwipe = new AnimatedFloat(
+ this::updateTranslationYForSwipe);
+
+ private boolean mHasSprungOnceThisGesture;
+ private @Nullable ValueAnimator mSpringBounce;
+ private boolean mGestureEnded;
+ private boolean mAnimationToHomeRunning;
+
+ private final boolean mIsTransientTaskbar;
+
+ private final TransitionCallback mCallback;
+
+ public TaskbarTranslationController(TaskbarActivityContext context) {
+ mContext = context;
+ mIsTransientTaskbar = DisplayController.isTransientTaskbar(mContext);
+ mCallback = new TransitionCallback();
+ }
+
+ /**
+ * Initialization method.
+ */
+ public void init(TaskbarControllers controllers) {
+ mControllers = controllers;
+ }
+
+ /**
+ * Called to cancel any existing animations.
+ */
+ public void cancelAnimationIfExists() {
+ if (mSpringBounce != null) {
+ mSpringBounce.cancel();
+ mSpringBounce = null;
+ }
+ reset();
+ }
+
+ private void updateTranslationYForSwipe() {
+ if (!mIsTransientTaskbar) {
+ return;
+ }
+
+ float transY = mTranslationYForSwipe.value;
+ mControllers.stashedHandleViewController.setTranslationYForSwipe(transY);
+ mControllers.taskbarViewController.setTranslationYForSwipe(transY);
+ mControllers.taskbarDragLayerController.setTranslationYForSwipe(transY);
+ }
+
+ /**
+ * Starts a spring aniamtion to set the views back to the resting state.
+ */
+ public void startSpring() {
+ if (mHasSprungOnceThisGesture || mAnimationToHomeRunning) {
+ return;
+ }
+ mSpringBounce = new SpringAnimationBuilder(mContext)
+ .setStartValue(mTranslationYForSwipe.value)
+ .setEndValue(0)
+ .setDampingRatio(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY)
+ .setStiffness(SpringForce.STIFFNESS_LOW)
+ .build(mTranslationYForSwipe, VALUE);
+ mSpringBounce.addListener(forEndCallback(() -> {
+ if (mGestureEnded) {
+ reset();
+ }
+ }));
+ mSpringBounce.start();
+ mHasSprungOnceThisGesture = true;
+ }
+
+ private void reset() {
+ mGestureEnded = false;
+ mHasSprungOnceThisGesture = false;
+ }
+
+ /**
+ * Returns a callback to help monitor the swipe gesture.
+ */
+ public TransitionCallback getTransitionCallback() {
+ return mCallback;
+ }
+
+ /**
+ * Returns an animation to reset the taskbar translation for animation back to launcher.
+ */
+ public ObjectAnimator createAnimToLauncher(long duration) {
+ ObjectAnimator animator = ObjectAnimator.ofFloat(mTranslationYForSwipe, VALUE, 0);
+ animator.setInterpolator(Interpolators.LINEAR);
+ animator.setDuration(duration);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ cancelAnimationIfExists();
+ mAnimationToHomeRunning = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimationToHomeRunning = false;
+ reset();
+ }
+ });
+ return animator;
+ }
+
+ /**
+ * Helper class to communicate to/from the input consumer.
+ */
+ public class TransitionCallback {
+
+ /**
+ * Called when there is movement to move the taskbar.
+ */
+ public void onActionMove(float dY) {
+ if (mAnimationToHomeRunning
+ || (mHasSprungOnceThisGesture && !mGestureEnded)) {
+ return;
+ }
+
+ mTranslationYForSwipe.updateValue(dY);
+ }
+
+ /**
+ * Called when swipe gesture has ended.
+ */
+ public void onActionEnd() {
+ if (mHasSprungOnceThisGesture) {
+ reset();
+ } else {
+ mGestureEnded = true;
+ startSpring();
+ }
+ }
+ }
+
+ @Override
+ public void dumpLogs(String prefix, PrintWriter pw) {
+ pw.println(prefix + "TaskbarTranslationController:");
+
+ pw.println(prefix + "\tmTranslationYForSwipe=" + mTranslationYForSwipe.value);
+ pw.println(prefix + "\tmHasSprungOnceThisGesture=" + mHasSprungOnceThisGesture);
+ pw.println(prefix + "\tmAnimationToHomeRunning=" + mAnimationToHomeRunning);
+ pw.println(prefix + "\tmGestureEnded=" + mGestureEnded);
+ pw.println(prefix + "\tmSpringBounce is running=" + (mSpringBounce != null
+ && mSpringBounce.isRunning()));
+ }
+}
+
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 1152126..4ec9b41 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -15,13 +15,18 @@
*/
package com.android.launcher3.taskbar;
+import android.content.Intent;
+import android.graphics.drawable.BitmapDrawable;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.CallSuper;
+import androidx.annotation.Nullable;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
import java.io.PrintWriter;
import java.util.stream.Stream;
@@ -105,6 +110,13 @@
return mControllers.taskbarStashController.isStashed();
}
+ /**
+ * Called at the end of the swipe gesture on Transient taskbar.
+ */
+ public void startTranslationSpring() {
+ mControllers.taskbarActivityContext.startTranslationSpring();
+ }
+
/*
* @param ev MotionEvent in screen coordinates.
* @return Whether any Taskbar item could handle the given MotionEvent if given the chance.
@@ -128,4 +140,38 @@
prefix,
getClass().getSimpleName()));
}
+
+ /**
+ * Returns RecentsView. Overwritten in LauncherTaskbarUIController and
+ * FallbackTaskbarUIController with Launcher-specific implementations. Returns null for other
+ * UI controllers (like DesktopTaskbarUIController) that don't have a RecentsView.
+ */
+ public @Nullable RecentsView getRecentsView() {
+ return null;
+ }
+
+ /**
+ * Uses the clicked Taskbar icon to launch a second app for splitscreen.
+ */
+ public void triggerSecondAppForSplit(ItemInfoWithIcon info, Intent intent, View startingView) {
+ RecentsView recents = getRecentsView();
+ TaskView foundTaskView = recents.getTaskViewByComponentName(info.getTargetComponent());
+ if (foundTaskView != null) {
+ recents.confirmSplitSelect(
+ foundTaskView,
+ foundTaskView.getTask(),
+ foundTaskView.getIconView().getDrawable(),
+ foundTaskView.getThumbnail(),
+ foundTaskView.getThumbnail().getThumbnail(),
+ /* intent */ null);
+ } else {
+ recents.confirmSplitSelect(
+ /* containerTaskView */ null,
+ /* task */ null,
+ new BitmapDrawable(info.bitmap.icon),
+ startingView,
+ /* thumbnail */ null,
+ intent);
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index a73528b..80a31b4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -91,6 +91,7 @@
this::updateTranslationY);
private AnimatedFloat mTaskbarNavButtonTranslationY;
private AnimatedFloat mTaskbarNavButtonTranslationYForInAppDisplay;
+ private float mTaskbarIconTranslationYForSwipe;
private final int mTaskbarBottomMargin;
@@ -260,9 +261,18 @@
mTaskbarView.setScaleY(scale);
}
+ /**
+ * Sets the translation of the TaskbarView during the swipe up gesture.
+ */
+ public void setTranslationYForSwipe(float transY) {
+ mTaskbarIconTranslationYForSwipe = transY;
+ updateTranslationY();
+ }
+
private void updateTranslationY() {
mTaskbarView.setTranslationY(mTaskbarIconTranslationYForHome.value
- + mTaskbarIconTranslationYForStash.value);
+ + mTaskbarIconTranslationYForStash.value
+ + mTaskbarIconTranslationYForSwipe);
}
private void updateIconsBackground() {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 7e4c2f6..b09e531 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -99,6 +99,7 @@
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.tracing.InputConsumerProto;
import com.android.launcher3.tracing.SwipeHandlerProto;
import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
@@ -662,6 +663,8 @@
true/* moveFocusedTask */,
new ActiveGestureLog.CompoundString(
"motion pause detected (animate=true)"));
+ Optional.ofNullable(mActivityInterface.getTaskbarController())
+ .ifPresent(TaskbarUIController::startTranslationSpring);
performHapticFeedback();
}
@@ -951,6 +954,8 @@
InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH, 2000 /* ms timeout */);
InteractionJankMonitorWrapper.begin(mRecentsView,
InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
+ InteractionJankMonitorWrapper.begin(mRecentsView,
+ InteractionJankMonitorWrapper.CUJ_APP_SWIPE_TO_RECENTS);
rv.post(() -> rv.getViewTreeObserver().removeOnDrawListener(this));
}
@@ -1055,6 +1060,10 @@
InteractionJankMonitorWrapper.cancel(
InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
}
+ if (endTarget != RECENTS) {
+ InteractionJankMonitorWrapper.cancel(
+ InteractionJankMonitorWrapper.CUJ_APP_SWIPE_TO_RECENTS);
+ }
switch (endTarget) {
case HOME:
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index cf1c137..4adfae5 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -170,6 +170,8 @@
mController.finish(toRecents, sendUserLeaveHint);
InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
+ InteractionJankMonitorWrapper.end(
+ InteractionJankMonitorWrapper.CUJ_APP_SWIPE_TO_RECENTS);
MAIN_EXECUTOR.execute(mPendingFinishCallbacks::executeAllAndDestroy);
});
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java
index 1430492..b7f2022 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java
@@ -27,9 +27,13 @@
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.taskbar.TaskbarActivityContext;
+import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback;
+import com.android.launcher3.touch.OverScroll;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.InputConsumer;
import com.android.systemui.shared.system.InputMonitorCompat;
@@ -48,7 +52,7 @@
private final float mUnstashArea;
private final float mScreenWidth;
- private final int mTaskbarThreshold;
+ private final int mTaskbarThresholdY;
private boolean mHasPassedTaskbarThreshold;
private final PointF mDownPos = new PointF();
@@ -57,6 +61,8 @@
private final boolean mIsTransientTaskbar;
+ private final @Nullable TransitionCallback mTransitionCallback;
+
public TaskbarStashInputConsumer(Context context, InputConsumer delegate,
InputMonitorCompat inputMonitor, TaskbarActivityContext taskbarActivityContext) {
super(delegate, inputMonitor);
@@ -66,7 +72,9 @@
Resources res = context.getResources();
mUnstashArea = res.getDimensionPixelSize(R.dimen.taskbar_unstash_input_area);
- mTaskbarThreshold = res.getDimensionPixelSize(R.dimen.taskbar_nav_threshold);
+ int taskbarThreshold = res.getDimensionPixelSize(R.dimen.taskbar_nav_threshold);
+ int screenHeight = taskbarActivityContext.getDeviceProfile().heightPx;
+ mTaskbarThresholdY = screenHeight - taskbarThreshold;
mIsTransientTaskbar = DisplayController.isTransientTaskbar(context);
@@ -76,6 +84,10 @@
onLongPressDetected(motionEvent);
}
});
+
+ mTransitionCallback = mIsTransientTaskbar
+ ? taskbarActivityContext.getTranslationCallbacks()
+ : null;
}
@Override
@@ -138,16 +150,25 @@
break;
}
mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
- float displacementY = mLastPos.y - mDownPos.y;
- float verticalDist = Math.abs(displacementY);
- boolean passedTaskbarThreshold = verticalDist >= mTaskbarThreshold;
- if (!mHasPassedTaskbarThreshold
- && passedTaskbarThreshold
- && mIsTransientTaskbar) {
- mHasPassedTaskbarThreshold = true;
+ if (mIsTransientTaskbar) {
+ float dY = mLastPos.y - mDownPos.y;
+ boolean passedTaskbarThreshold = dY < 0
+ && mLastPos.y < mTaskbarThresholdY;
- mTaskbarActivityContext.onSwipeToUnstashTaskbar();
+ if (!mHasPassedTaskbarThreshold
+ && passedTaskbarThreshold) {
+ mHasPassedTaskbarThreshold = true;
+
+ mTaskbarActivityContext.onSwipeToUnstashTaskbar();
+ }
+
+ if (dY < 0) {
+ dY = -OverScroll.dampedScroll(-dY, mTaskbarThresholdY);
+ if (mTransitionCallback != null) {
+ mTransitionCallback.onActionMove(dY);
+ }
+ }
}
break;
case MotionEvent.ACTION_UP:
@@ -158,6 +179,9 @@
}
mTaskbarActivityContext.setAutohideSuspendFlag(
FLAG_AUTOHIDE_SUSPEND_TOUCHING, false);
+ if (mTransitionCallback != null) {
+ mTransitionCallback.onActionEnd();
+ }
mHasPassedTaskbarThreshold = false;
break;
}
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 5c37da1..b476c12 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -322,7 +322,7 @@
boolean isRtlEnabled = !mIsRecentsRtl;
mPositionHelper.updateThumbnailMatrix(
mThumbnailPosition, mThumbnailData, mTaskRect.width(), mTaskRect.height(),
- mDp.widthPx, mDp.taskbarSize, mDp.isTablet,
+ mDp.widthPx, mDp.heightPx, mDp.taskbarSize, mDp.isTablet,
mOrientationState.getRecentsActivityRotation(), isRtlEnabled);
mPositionHelper.getMatrix().invert(mInversePositionMatrix);
if (DEBUG) {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 35414a6..ff0c984 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -74,9 +74,12 @@
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.WindowConfiguration;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.LocusId;
import android.content.res.Configuration;
+import android.graphics.Bitmap;
import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -122,6 +125,7 @@
import androidx.annotation.UiThread;
import androidx.core.graphics.ColorUtils;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseActivity.MultiWindowModeChangedListener;
import com.android.launcher3.DeviceProfile;
@@ -661,8 +665,6 @@
private TaskView mSecondSplitHiddenView;
@Nullable
private SplitBounds mSplitBoundsConfig;
- private final Toast mSplitToast = Toast.makeText(getContext(),
- R.string.toast_split_select_app, Toast.LENGTH_SHORT);
private final Toast mSplitUnsupportedToast = Toast.makeText(getContext(),
R.string.toast_split_app_unsupported, Toast.LENGTH_SHORT);
@@ -1212,6 +1214,21 @@
return null;
}
+ /**
+ * Returns a {@link TaskView} that has ComponentName matching {@code componentName} or null if
+ * no match.
+ */
+ @Nullable
+ public TaskView getTaskViewByComponentName(ComponentName componentName) {
+ for (int i = 0; i < getTaskViewCount(); i++) {
+ TaskView taskView = requireTaskViewAt(i);
+ if (taskView.getTask().key.sourceComponent.equals(componentName)) {
+ return taskView;
+ }
+ }
+ return null;
+ }
+
public void setOverviewStateEnabled(boolean enabled) {
mOverviewStateEnabled = enabled;
updateTaskStackListenerState();
@@ -2241,8 +2258,14 @@
for (int i = 0; i < getTaskViewCount(); i++) {
requireTaskViewAt(i).setOrientationState(mOrientationState);
}
+ boolean shouldRotateMenuForFakeRotation =
+ !mOrientationState.isRecentsActivityRotationAllowed();
+ if (!shouldRotateMenuForFakeRotation) {
+ return;
+ }
TaskMenuView tv = (TaskMenuView) getTopOpenViewWithType(mActivity, TYPE_TASK_MENU);
if (tv != null) {
+ // Rotation is supported on phone (details at b/254198019#comment4)
tv.onRotationChanged();
}
}
@@ -3521,7 +3544,8 @@
mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SELECT_ACTIVE, isSplitSelectionActive());
mActionsView.updateSplitButtonHiddenFlags(FLAG_IS_NOT_TABLET,
!mActivity.getDeviceProfile().isTablet);
- mActionsView.updateSplitButtonDisabledFlags(FLAG_SINGLE_TASK, getTaskViewCount() <= 1);
+ mActionsView.updateSplitButtonDisabledFlags(FLAG_SINGLE_TASK,
+ !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get() && getTaskViewCount() <= 1);
}
/**
@@ -4230,24 +4254,39 @@
* Confirms the selection of the next split task. The extra data is passed through because the
* user may be selecting a subtask in a group.
*
+ * @param containerTaskView If our second selected app is currently running in Recents, this is
+ * the "container" TaskView from Recents. If we are starting a fresh
+ * instance of the app from an Intent, this will be null.
+ * @param task The Task corresponding to our second selected app. If we are starting a fresh
+ * instance of the app from an Intent, this will be null.
+ * @param drawable The Drawable corresponding to our second selected app's icon.
+ * @param secondView The View representing the current space on the screen where the second app
+ * is (either the ThumbnailView or the tapped icon).
+ * @param intent If we are launching a fresh instance of the app, this is the Intent for it. If
+ * the second app is already running in Recents, this will be null.
* @return true if waiting for confirmation of second app or if split animations are running,
* false otherwise
*/
- public boolean confirmSplitSelect(TaskView containerTaskView, Task task, IconView iconView,
- TaskThumbnailView thumbnailView) {
+ public boolean confirmSplitSelect(TaskView containerTaskView, Task task, Drawable drawable,
+ View secondView, @Nullable Bitmap thumbnail, Intent intent) {
if (canLaunchFullscreenTask()) {
return false;
}
if (mSplitSelectStateController.isBothSplitAppsConfirmed()) {
return true;
}
- mSplitToast.cancel();
- if (!task.isDockable) {
- // Task not split screen supported
- mSplitUnsupportedToast.show();
- return true;
+ // Second task is selected either as an already-running Task or an Intent
+ if (task != null) {
+ if (!task.isDockable) {
+ // Task does not support split screen
+ mSplitUnsupportedToast.show();
+ return true;
+ }
+ mSplitSelectStateController.setSecondTask(task);
+ } else {
+ mSplitSelectStateController.setSecondTask(intent);
}
- mSplitSelectStateController.setSecondTask(task);
+
RectF secondTaskStartingBounds = new RectF();
Rect secondTaskEndingBounds = new Rect();
// TODO(194414938) starting bounds seem slightly off, investigate
@@ -4274,9 +4313,9 @@
false /* fadeWithThumbnail */, true /* isStagedTask */);
safeRemoveDragLayerView(mSecondFloatingTaskView);
- mSecondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
- thumbnailView, thumbnailView.getThumbnail(),
- iconView.getDrawable(), secondTaskStartingBounds);
+
+ mSecondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity, secondView,
+ thumbnail, drawable, secondTaskStartingBounds);
mSecondFloatingTaskView.setAlpha(1);
mSecondFloatingTaskView.addConfirmAnimation(pendingAnimation, secondTaskStartingBounds,
secondTaskEndingBounds, true /* fadeWithThumbnail */, false /* isStagedTask */);
@@ -4292,7 +4331,9 @@
});
mSecondSplitHiddenView = containerTaskView;
- mSecondSplitHiddenView.setThumbnailVisibility(INVISIBLE);
+ if (mSecondSplitHiddenView != null) {
+ mSecondSplitHiddenView.setThumbnailVisibility(INVISIBLE);
+ }
InteractionJankMonitorWrapper.begin(this,
InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "Second tile selected");
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 6792dc5..904c944 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -473,8 +473,8 @@
boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
DeviceProfile dp = mActivity.getDeviceProfile();
mPreviewPositionHelper.updateThumbnailMatrix(mPreviewRect, mThumbnailData,
- getMeasuredWidth(), getMeasuredHeight(), dp.widthPx, dp.taskbarSize,
- dp.isTablet, currentRotation, isRtl);
+ getMeasuredWidth(), getMeasuredHeight(), dp.widthPx, dp.heightPx,
+ dp.taskbarSize, dp.isTablet, currentRotation, isRtl);
mBitmapShader.setLocalMatrix(mPreviewPositionHelper.getMatrix());
mPaint.setShader(mBitmapShader);
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 527a0d1..583771e 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -621,7 +621,8 @@
TaskIdAttributeContainer container = mTaskIdAttributeContainer[index];
if (container != null) {
return getRecentsView().confirmSplitSelect(this, container.getTask(),
- container.getIconView(), container.getThumbnailView());
+ container.getIconView().getDrawable(), container.getThumbnailView(),
+ container.getThumbnailView().getThumbnail(), /* intent */ null);
}
return false;
}
diff --git a/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt b/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
index 4785350..963da27 100644
--- a/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
@@ -57,7 +57,7 @@
val isRtl = false
mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
- canvasHeight, dp.widthPx, dp.taskbarSize, dp.isTablet, currentRotation,
+ canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
isRtl)
params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
/* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper)
@@ -78,7 +78,7 @@
val isRtl = false
mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
- canvasHeight, dp.widthPx, dp.taskbarSize, dp.isTablet, currentRotation,
+ canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
isRtl)
params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
/* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper)
diff --git a/res/color-night-v31/transient_taskbar_background.xml b/res/color-night-v31/transient_taskbar_background.xml
new file mode 100644
index 0000000..40f6494
--- /dev/null
+++ b/res/color-night-v31/transient_taskbar_background.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral1_500" android:lStar="15" />
+</selector>
+
diff --git a/res/layout/user_folder_icon_normalized.xml b/res/layout/user_folder_icon_normalized.xml
index 39f93d9..5518dc8 100644
--- a/res/layout/user_folder_icon_normalized.xml
+++ b/res/layout/user_folder_icon_normalized.xml
@@ -30,11 +30,11 @@
<LinearLayout
android:id="@+id/folder_footer"
android:layout_width="match_parent"
- android:layout_height="@dimen/folder_label_height"
+ android:layout_height="@dimen/folder_footer_height_default"
android:clipChildren="false"
android:orientation="horizontal"
- android:paddingLeft="12dp"
- android:paddingRight="12dp">
+ android:paddingLeft="@dimen/folder_footer_horiz_padding"
+ android:paddingRight="@dimen/folder_footer_horiz_padding">
<com.android.launcher3.folder.FolderNameEditText
android:id="@+id/folder_name"
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 7b2ed8b..09b2d6f 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -43,4 +43,7 @@
<!-- Bottom sheet-->
<dimen name="bottom_sheet_extra_top_padding">300dp</dimen>
+
+ <!-- Folder spaces -->
+ <dimen name="folder_footer_horiz_padding">24dp</dimen>
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 283c793..f270b10 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -141,9 +141,12 @@
<attr name="numColumns" format="integer" />
<!-- numSearchContainerColumns defaults to numColumns, if not specified -->
<attr name="numSearchContainerColumns" format="integer" />
+
<!-- numFolderRows & numFolderColumns defaults to numRows & numColumns, if not specified -->
<attr name="numFolderRows" format="integer" />
<attr name="numFolderColumns" format="integer" />
+ <attr name="folderStyle" format="reference" />
+
<!-- numAllAppsColumns defaults to numColumns, if not specified -->
<attr name="numAllAppsColumns" format="integer" />
<!-- Number of columns to use when extending the all-apps size,
@@ -333,19 +336,6 @@
if not specified -->
<attr name="allAppsBorderSpaceTwoPanelLandscapeVertical" format="float" />
- <!-- defaults to minCellHeight if not specified
- when GridDisplayOption#isScalable is true. -->
- <attr name="folderCellHeight" format="float" />
- <!-- defaults to minCellWidth, if not specified -->
- <attr name="folderCellWidth" format="float" />
-
- <!-- defaults to borderSpace, if not specified -->
- <!-- space to be used horizontally and vertically -->
- <attr name="folderBorderSpace" format="float" />
-
- <!-- defaults to folderBorderSpace vertical, if not specified -->
- <attr name="folderTopPadding" format="float" />
-
<!-- defaults to res.hotseat_bar_bottom_space_default, if not specified -->
<attr name="hotseatBarBottomSpace" format="float" />
<!-- defaults to hotseatBarBottomSpace, if not specified -->
@@ -394,6 +384,22 @@
</declare-styleable>
+ <declare-styleable name="FolderDisplayStyle">
+ <!-- defaults to minCellHeight if not specified
+ when GridDisplayOption#isScalable is true. -->
+ <attr name="folderCellHeight" format="dimension" />
+ <!-- defaults to minCellWidth, if not specified -->
+ <attr name="folderCellWidth" format="dimension" />
+ <!-- space to be used horizontally and vertically between icons,
+ and to the left and right of folder -->
+ <attr name="folderBorderSpace" format="dimension" />
+ <!-- height of the footer of the folder -->
+ <attr name="folderFooterHeight" format="dimension" />
+ <!-- padding on top of the folder -->
+ <attr name="folderTopPadding" format="dimension" />
+ </declare-styleable>
+
+
<declare-styleable name="CellLayout">
<attr name="containerType" format="integer">
<enum name="workspace" value="0" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 8f48ec8..033346a 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -255,7 +255,7 @@
<dimen name="folder_cell_y_padding">6dp</dimen>
<!-- label text size = workspace text size multiplied by this scale -->
<dimen name="folder_label_text_scale">1.14</dimen>
- <dimen name="folder_label_height">56dp</dimen>
+ <dimen name="folder_footer_height_default">56dp</dimen>
<dimen name="folder_content_padding_left_right">8dp</dimen>
<dimen name="folder_content_padding_top">16dp</dimen>
@@ -441,4 +441,8 @@
<!-- State transition -->
<item name="workspace_content_scale" format="float" type="dimen">0.97</item>
+
+ <!-- Folder spaces -->
+ <dimen name="folder_top_padding_default">24dp</dimen>
+ <dimen name="folder_footer_horiz_padding">20dp</dimen>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index d0be420..9e75a31 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -309,4 +309,13 @@
<item name="android:windowLightStatusBar">true</item>
<item name="android:windowTranslucentStatus">true</item>
</style>
+
+ <style name="FolderDefaultStyle">
+ <item name="folderTopPadding">24dp</item>
+ <item name="folderCellHeight">94dp</item>
+ <item name="folderCellWidth">80dp</item>
+ <item name="folderBorderSpace">16dp</item>
+ <item name="folderFooterHeight">56dp</item>
+ </style>
+
</resources>
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index de2a1f9..2103593 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -373,7 +373,8 @@
private void resetCellSizeInternal(DeviceProfile deviceProfile) {
switch (mContainerType) {
case FOLDER:
- mBorderSpace = new Point(deviceProfile.folderCellLayoutBorderSpacePx);
+ mBorderSpace = new Point(deviceProfile.folderCellLayoutBorderSpacePx,
+ deviceProfile.folderCellLayoutBorderSpacePx);
break;
case HOTSEAT:
mBorderSpace = new Point(deviceProfile.hotseatBorderSpace,
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 2b9eb29..c91e3eb 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -25,12 +25,14 @@
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
import static com.android.launcher3.icons.GraphicsUtils.getShapePath;
+import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURCE_HANDLE;
import static com.android.launcher3.testing.shared.ResourceUtils.pxFromDp;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -61,6 +63,7 @@
private static final int DEFAULT_DOT_SIZE = 100;
private static final float ALL_APPS_TABLET_MAX_ROWS = 5.5f;
+ private static final float MIN_FOLDER_TEXT_SIZE_SP = 16f;
public static final PointF DEFAULT_SCALE = new PointF(1.0f, 1.0f);
public static final ViewScaleProvider DEFAULT_PROVIDER = itemInfo -> DEFAULT_SCALE;
@@ -147,11 +150,12 @@
// Folder
public float folderLabelTextScale;
public int folderLabelTextSizePx;
+ public int folderFooterHeightPx;
public int folderIconSizePx;
public int folderIconOffsetYPx;
// Folder content
- public Point folderCellLayoutBorderSpacePx;
+ public int folderCellLayoutBorderSpacePx;
public int folderContentPaddingLeftRight;
public int folderContentPaddingTop;
@@ -352,17 +356,34 @@
}
folderLabelTextScale = res.getFloat(R.dimen.folder_label_text_scale);
- folderContentPaddingLeftRight =
- res.getDimensionPixelSize(R.dimen.folder_content_padding_left_right);
- folderContentPaddingTop = res.getDimensionPixelSize(R.dimen.folder_content_padding_top);
+
+ if (inv.folderStyle != INVALID_RESOURCE_HANDLE) {
+ TypedArray folderStyle = context.obtainStyledAttributes(inv.folderStyle,
+ R.styleable.FolderDisplayStyle);
+ // These are re-set in #updateFolderCellSize if the grid is not scalable
+ folderCellHeightPx = folderStyle.getDimensionPixelSize(
+ R.styleable.FolderDisplayStyle_folderCellHeight, 0);
+ folderCellWidthPx = folderStyle.getDimensionPixelSize(
+ R.styleable.FolderDisplayStyle_folderCellWidth, 0);
+
+ folderContentPaddingTop = folderStyle.getDimensionPixelSize(
+ R.styleable.FolderDisplayStyle_folderTopPadding, 0);
+ folderCellLayoutBorderSpacePx = folderStyle.getDimensionPixelSize(
+ R.styleable.FolderDisplayStyle_folderBorderSpace, 0);
+ folderFooterHeightPx = folderStyle.getDimensionPixelSize(
+ R.styleable.FolderDisplayStyle_folderFooterHeight, 0);
+ folderStyle.recycle();
+ } else {
+ folderCellLayoutBorderSpacePx = 0;
+ folderFooterHeightPx = 0;
+ folderContentPaddingTop = res.getDimensionPixelSize(R.dimen.folder_top_padding_default);
+ }
cellLayoutBorderSpacePx = getCellLayoutBorderSpace(inv);
+ cellLayoutBorderSpaceOriginalPx = new Point(cellLayoutBorderSpacePx);
allAppsBorderSpacePx = new Point(
pxFromDp(inv.allAppsBorderSpaces[mTypeIndex].x, mMetrics),
pxFromDp(inv.allAppsBorderSpaces[mTypeIndex].y, mMetrics));
- cellLayoutBorderSpaceOriginalPx = new Point(cellLayoutBorderSpacePx);
- folderCellLayoutBorderSpacePx = new Point(pxFromDp(inv.folderBorderSpaces.x, mMetrics),
- pxFromDp(inv.folderBorderSpaces.y, mMetrics));
workspacePageIndicatorHeight = res.getDimensionPixelSize(
R.dimen.workspace_page_indicator_height);
@@ -931,22 +952,20 @@
private void updateAvailableFolderCellDimensions(Resources res) {
updateFolderCellSize(1f, res);
- final int folderBottomPanelSize = res.getDimensionPixelSize(R.dimen.folder_label_height);
-
// Don't let the folder get too close to the edges of the screen.
int folderMargin = edgeMarginPx * 2;
Point totalWorkspacePadding = getTotalWorkspacePadding();
// Check if the icons fit within the available height.
float contentUsedHeight = folderCellHeightPx * inv.numFolderRows
- + ((inv.numFolderRows - 1) * folderCellLayoutBorderSpacePx.y);
- int contentMaxHeight = availableHeightPx - totalWorkspacePadding.y - folderBottomPanelSize
+ + ((inv.numFolderRows - 1) * folderCellLayoutBorderSpacePx);
+ int contentMaxHeight = availableHeightPx - totalWorkspacePadding.y - folderFooterHeightPx
- folderMargin - folderContentPaddingTop;
float scaleY = contentMaxHeight / contentUsedHeight;
// Check if the icons fit within the available width.
float contentUsedWidth = folderCellWidthPx * inv.numFolderColumns
- + ((inv.numFolderColumns - 1) * folderCellLayoutBorderSpacePx.x);
+ + ((inv.numFolderColumns - 1) * folderCellLayoutBorderSpacePx);
int contentMaxWidth = availableWidthPx - totalWorkspacePadding.x - folderMargin
- folderContentPaddingLeftRight * 2;
float scaleX = contentMaxWidth / contentUsedWidth;
@@ -964,19 +983,18 @@
folderChildIconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mMetrics, scale));
folderChildTextSizePx =
pxFromSp(inv.iconTextSize[INDEX_DEFAULT], mMetrics, scale);
- folderLabelTextSizePx = (int) (folderChildTextSizePx * folderLabelTextScale);
+ folderLabelTextSizePx = Math.max(pxFromSp(MIN_FOLDER_TEXT_SIZE_SP, mMetrics),
+ (int) (folderChildTextSizePx * folderLabelTextScale));
int textHeight = Utilities.calculateTextHeight(folderChildTextSizePx);
if (isScalableGrid) {
- folderCellWidthPx = pxFromDp(inv.folderCellSize.x, mMetrics, scale);
- folderCellHeightPx = pxFromDp(inv.folderCellSize.y, mMetrics, scale);
+ if (inv.folderStyle == INVALID_RESOURCE_HANDLE) {
+ folderCellWidthPx = pxFromDp(getCellSize().x, mMetrics, scale);
+ folderCellHeightPx = pxFromDp(getCellSize().y, mMetrics, scale);
+ }
- folderCellLayoutBorderSpacePx = new Point(
- pxFromDp(inv.folderBorderSpaces.x, mMetrics, scale),
- pxFromDp(inv.folderBorderSpaces.y, mMetrics, scale));
- folderContentPaddingLeftRight = folderCellLayoutBorderSpacePx.x;
- folderContentPaddingTop = pxFromDp(inv.folderTopPadding, mMetrics, scale);
+ folderContentPaddingLeftRight = folderCellLayoutBorderSpacePx;
} else {
int cellPaddingX = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_x_padding)
* scale);
@@ -985,6 +1003,10 @@
folderCellWidthPx = folderChildIconSizePx + 2 * cellPaddingX;
folderCellHeightPx = folderChildIconSizePx + 2 * cellPaddingY + textHeight;
+ folderContentPaddingLeftRight =
+ res.getDimensionPixelSize(R.dimen.folder_content_padding_left_right);
+ folderFooterHeightPx =
+ res.getDimensionPixelSize(R.dimen.folder_footer_height_default);
}
folderChildDrawablePaddingPx = Math.max(0,
@@ -1468,13 +1490,12 @@
writer.println(prefix + pxToDpStr("folderChildTextSizePx", folderChildTextSizePx));
writer.println(prefix + pxToDpStr("folderChildDrawablePaddingPx",
folderChildDrawablePaddingPx));
- writer.println(prefix + pxToDpStr("folderCellLayoutBorderSpacePx Horizontal",
- folderCellLayoutBorderSpacePx.x));
- writer.println(prefix + pxToDpStr("folderCellLayoutBorderSpacePx Vertical",
- folderCellLayoutBorderSpacePx.y));
+ writer.println(prefix + pxToDpStr("folderCellLayoutBorderSpacePx",
+ folderCellLayoutBorderSpacePx));
writer.println(prefix + pxToDpStr("folderContentPaddingLeftRight",
folderContentPaddingLeftRight));
writer.println(prefix + pxToDpStr("folderTopPadding", folderContentPaddingTop));
+ writer.println(prefix + pxToDpStr("folderFooterHeight", folderFooterHeightPx));
writer.println(prefix + pxToDpStr("bottomSheetTopPadding", bottomSheetTopPadding));
writer.println(prefix + "\tbottomSheetOpenDuration: " + bottomSheetOpenDuration);
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 635f400..ca92aa4 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.Utilities.dpiFromPx;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TWO_PANEL_HOME;
+import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURCE_HANDLE;
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS;
@@ -43,8 +44,10 @@
import android.util.Xml;
import android.view.Display;
+import androidx.annotation.DimenRes;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
+import androidx.annotation.StyleRes;
import androidx.annotation.VisibleForTesting;
import androidx.core.content.res.ResourcesCompat;
@@ -129,11 +132,9 @@
public PointF[] minCellSize;
public PointF[] borderSpaces;
- public int inlineNavButtonsEndSpacing;
+ public @DimenRes int inlineNavButtonsEndSpacing;
- public PointF folderBorderSpaces;
- public PointF folderCellSize;
- public float folderTopPadding;
+ public @StyleRes int folderStyle;
public float[] horizontalMargin;
@@ -323,6 +324,11 @@
return displayOption.grid.name;
}
+ @VisibleForTesting
+ public static String getDefaultGridName(Context context) {
+ return new InvariantDeviceProfile().initGrid(context, null);
+ }
+
private void initGrid(Context context, Info displayInfo, DisplayOption displayOption,
@DeviceType int deviceType) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
@@ -333,8 +339,11 @@
dbFile = closestProfile.dbFile;
defaultLayoutId = closestProfile.defaultLayoutId;
demoModeLayoutId = closestProfile.demoModeLayoutId;
+
numFolderRows = closestProfile.numFolderRows;
numFolderColumns = closestProfile.numFolderColumns;
+ folderStyle = closestProfile.folderStyle;
+
isScalable = closestProfile.isScalable;
devicePaddingId = closestProfile.devicePaddingId;
this.deviceType = deviceType;
@@ -357,10 +366,6 @@
borderSpaces = displayOption.borderSpaces;
- folderBorderSpaces = displayOption.folderBorderSpaces;
- folderCellSize = displayOption.folderCellSize;
- folderTopPadding = displayOption.folderTopPadding;
-
horizontalMargin = displayOption.horizontalMargin;
numShownHotseatIcons = closestProfile.numHotseatIcons;
@@ -749,6 +754,7 @@
private final int numFolderRows;
private final int numFolderColumns;
+ private final @StyleRes int folderStyle;
private final int numAllAppsColumns;
private final int numDatabaseAllAppsColumns;
@@ -759,7 +765,7 @@
private final boolean[] inlineQsb = new boolean[COUNT_SIZES];
- private int inlineNavButtonsEndSpacing;
+ private @DimenRes int inlineNavButtonsEndSpacing;
private final String dbFile;
private final int defaultLayoutId;
@@ -811,11 +817,15 @@
inlineNavButtonsEndSpacing =
a.getResourceId(R.styleable.GridDisplayOption_inlineNavButtonsEndSpacing,
R.dimen.taskbar_button_margin_default);
+
numFolderRows = a.getInt(
R.styleable.GridDisplayOption_numFolderRows, numRows);
numFolderColumns = a.getInt(
R.styleable.GridDisplayOption_numFolderColumns, numColumns);
+ folderStyle = a.getResourceId(R.styleable.GridDisplayOption_folderStyle,
+ INVALID_RESOURCE_HANDLE);
+
isScalable = a.getBoolean(
R.styleable.GridDisplayOption_isScalable, false);
devicePaddingId = a.getResourceId(
@@ -860,10 +870,6 @@
private final PointF[] minCellSize = new PointF[COUNT_SIZES];
- private final PointF folderCellSize;
- private final PointF folderBorderSpaces;
- private float folderTopPadding;
-
private final PointF[] borderSpaces = new PointF[COUNT_SIZES];
private final float[] horizontalMargin = new float[COUNT_SIZES];
private final float[] hotseatBarBottomSpace = new float[COUNT_SIZES];
@@ -946,21 +952,6 @@
borderSpaceTwoPanelLandscape);
borderSpaces[INDEX_TWO_PANEL_LANDSCAPE] = new PointF(x, y);
- x = a.getFloat(R.styleable.ProfileDisplayOption_folderCellWidth,
- minCellSize[INDEX_DEFAULT].x);
- y = a.getFloat(R.styleable.ProfileDisplayOption_folderCellHeight,
- minCellSize[INDEX_DEFAULT].y);
- folderCellSize = new PointF(x, y);
-
- float folderBorderSpace = a.getFloat(R.styleable.ProfileDisplayOption_folderBorderSpace,
- borderSpace);
-
- x = y = folderBorderSpace;
- folderBorderSpaces = new PointF(x, y);
-
- folderTopPadding = a.getFloat(R.styleable.ProfileDisplayOption_folderTopPadding,
- folderBorderSpaces.y);
-
x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidth,
minCellSize[INDEX_DEFAULT].x);
y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeight,
@@ -1133,9 +1124,6 @@
allAppsIconTextSizes[i] = 0;
allAppsBorderSpaces[i] = new PointF();
}
- folderBorderSpaces = new PointF();
- folderCellSize = new PointF();
- folderTopPadding = 0f;
}
private DisplayOption multiply(float w) {
@@ -1156,11 +1144,6 @@
allAppsBorderSpaces[i].x *= w;
allAppsBorderSpaces[i].y *= w;
}
- folderBorderSpaces.x *= w;
- folderBorderSpaces.y *= w;
- folderCellSize.x *= w;
- folderCellSize.y *= w;
- folderTopPadding *= w;
return this;
}
@@ -1183,11 +1166,6 @@
allAppsBorderSpaces[i].x += p.allAppsBorderSpaces[i].x;
allAppsBorderSpaces[i].y += p.allAppsBorderSpaces[i].y;
}
- folderBorderSpaces.x += p.folderBorderSpaces.x;
- folderBorderSpaces.y += p.folderBorderSpaces.y;
- folderCellSize.x += p.folderCellSize.x;
- folderCellSize.y += p.folderCellSize.y;
- folderTopPadding += p.folderTopPadding;
return this;
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c73e077..ab7f622 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -482,6 +482,9 @@
mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs);
+ // TODO: move the SearchConfig to SearchState when new LauncherState is created.
+ mBaseSearchConfig = new BaseSearchConfig();
+
mAppWidgetManager = new WidgetManagerHelper(this);
mAppWidgetHolder = createAppWidgetHolder();
mAppWidgetHolder.startListening();
@@ -548,9 +551,6 @@
getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
}
setTitle(R.string.home_screen);
-
- // TODO: move the SearchConfig to SearchState when new LauncherState is created.
- mBaseSearchConfig = new BaseSearchConfig();
}
protected LauncherOverlayManager getDefaultOverlay() {
@@ -1598,7 +1598,6 @@
&& AbstractFloatingView.getTopOpenView(this) == null;
boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction());
boolean internalStateHandled = ACTIVITY_TRACKER.handleNewIntent(this);
- hideKeyboard();
if (isActionMain) {
if (!internalStateHandled) {
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 8b342ea..7a74d7e 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -152,7 +152,7 @@
// No need to add padding when cell layout border spacing is present.
boolean noPaddingX =
(dp.cellLayoutBorderSpacePx.x > 0 && mContainerType == WORKSPACE)
- || (dp.folderCellLayoutBorderSpacePx.x > 0 && mContainerType == FOLDER)
+ || (dp.folderCellLayoutBorderSpacePx > 0 && mContainerType == FOLDER)
|| (dp.hotseatBorderSpace > 0 && mContainerType == HOTSEAT);
int cellPaddingX = noPaddingX
? 0
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index f70511a..a507532 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -521,6 +521,11 @@
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
+ /** Converts a dp value to pixels for a certain density. */
+ public static int dpToPx(float dp, int densityDpi) {
+ float densityRatio = (float) densityDpi / DisplayMetrics.DENSITY_DEFAULT;
+ return (int) (dp * densityRatio);
+ }
public static int pxFromSp(float size, DisplayMetrics metrics) {
return pxFromSp(size, metrics, 1f);
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 368a373..e34d4c8 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -31,6 +31,7 @@
import com.android.launcher3.util.ScrollableLayoutManager;
import com.android.launcher3.views.ActivityContext;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -43,6 +44,31 @@
public static final String TAG = "AppsGridAdapter";
private final AppsGridLayoutManager mGridLayoutMgr;
+ private final List<OnLayoutCompletedListener> mOnLayoutCompletedListeners = new ArrayList<>();
+
+ /**
+ * Listener for {@link RecyclerView.LayoutManager#onLayoutCompleted(RecyclerView.State)}
+ */
+ public interface OnLayoutCompletedListener {
+ void onLayoutCompleted();
+ }
+
+ /**
+ * Adds a {@link OnLayoutCompletedListener} to receive a callback when {@link
+ * RecyclerView.LayoutManager#onLayoutCompleted(RecyclerView.State)} is called
+ */
+ public void addOnLayoutCompletedListener(OnLayoutCompletedListener listener) {
+ mOnLayoutCompletedListeners.add(listener);
+ }
+
+ /**
+ * Removes a {@link OnLayoutCompletedListener} to not receive a callback when {@link
+ * RecyclerView.LayoutManager#onLayoutCompleted(RecyclerView.State)} is called
+ */
+ public void removeOnLayoutCompletedListener(OnLayoutCompletedListener listener) {
+ mOnLayoutCompletedListeners.remove(listener);
+ }
+
public AllAppsGridAdapter(T activityContext, LayoutInflater inflater,
AlphabeticalAppsList apps, BaseAdapterProvider[] adapterProviders) {
@@ -133,6 +159,14 @@
}
@Override
+ public void onLayoutCompleted(RecyclerView.State state) {
+ super.onLayoutCompleted(state);
+ for (OnLayoutCompletedListener listener : mOnLayoutCompletedListeners) {
+ listener.onLayoutCompleted();
+ }
+ }
+
+ @Override
protected int incrementTotalHeight(Adapter adapter, int position, int heightUntilLastPos) {
AllAppsGridAdapter.AdapterItem item = mApps.getAdapterItems().get(position);
// only account for the first icon in the row since they are the same size within a row
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index fa2c6e9..9930abe 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -141,6 +141,9 @@
private final Launcher mLauncher;
private boolean mIsVerticalLayout;
+ // Whether this class should take care of closing the keyboard.
+ private boolean mShouldControlKeyboard;
+
// Animation in this class is controlled by a single variable {@link mProgress}.
// Visually, it represents top y coordinate of the all apps container if multiplied with
// {@link mShiftRange}.
@@ -238,7 +241,7 @@
StateAnimationConfig config, PendingAnimation builder) {
if (mLauncher.isInState(ALL_APPS) && !ALL_APPS.equals(toState)) {
// For atomic animations, we close the keyboard immediately.
- if (!config.userControlled && !mLauncher.getSearchConfig().isKeyboardSyncEnabled()) {
+ if (!config.userControlled && mShouldControlKeyboard) {
mLauncher.getAppsView().getSearchUiManager().getEditText().hideKeyboard();
}
@@ -252,7 +255,7 @@
// the keyboard open and then changes their mind and swipes back up, we want the
// keyboard to remain open. However an onCancel signal is sent to the listeners
// (success = false), so we need to check for that.
- if (config.userControlled && success) {
+ if (config.userControlled && success && mShouldControlKeyboard) {
mLauncher.getAppsView().getSearchUiManager().getEditText().hideKeyboard();
}
});
@@ -317,6 +320,8 @@
mAppsViewAlpha.setUpdateVisibility(true);
mAppsViewTranslationY = new MultiPropertyFactory<>(
mAppsView, VIEW_TRANSLATE_Y, APPS_VIEW_INDEX_COUNT, Float::sum);
+
+ mShouldControlKeyboard = !mLauncher.getSearchConfig().isKeyboardSyncEnabled();
}
/**
@@ -333,7 +338,9 @@
private void onProgressAnimationEnd() {
if (Float.compare(mProgress, 1f) == 0) {
mAppsView.reset(false /* animate */);
- mLauncher.getAppsView().getSearchUiManager().getEditText().hideKeyboard();
+ if (mShouldControlKeyboard) {
+ mLauncher.getAppsView().getSearchUiManager().getEditText().hideKeyboard();
+ }
}
}
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 4287779..3a58020 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -323,6 +323,9 @@
public static final BooleanFlag SHOW_DOT_PAGINATION = getDebugFlag(
"SHOW_DOT_PAGINATION", false, "Enable showing dot pagination in workspace");
+ public static final BooleanFlag ENABLE_TOAST_IMPRESSION_LOGGING = getDebugFlag(
+ "ENABLE_TOAST_IMPRESSION_LOGGING", false, "Enable toast impression logging");
+
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 7e14912..99822da 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -292,7 +292,7 @@
mFolderName.forceDisableSuggestions(true);
mFooter = findViewById(R.id.folder_footer);
- mFooterHeight = getResources().getDimensionPixelSize(R.dimen.folder_label_height);
+ mFooterHeight = dp.folderFooterHeightPx;
if (Utilities.ATLEAST_R) {
mKeyboardInsetAnimationCallback = new KeyboardInsetAnimationCallback(this);
@@ -1167,14 +1167,6 @@
mContent.setFixedSize(contentWidth, contentHeight);
mContent.measure(contentAreaWidthSpec, contentAreaHeightSpec);
- if (mContent.getChildCount() > 0) {
- int cellIconGap = (mContent.getPageAt(0).getCellWidth()
- - mActivityContext.getDeviceProfile().iconSizePx) / 2;
- mFooter.setPadding(mContent.getPaddingLeft() + cellIconGap,
- mFooter.getPaddingTop(),
- mContent.getPaddingRight() + cellIconGap,
- mFooter.getPaddingBottom());
- }
mFooter.measure(contentAreaWidthSpec,
MeasureSpec.makeMeasureSpec(mFooterHeight, MeasureSpec.EXACTLY));
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index d5ef9df..4829c42 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -234,9 +234,9 @@
mFolder, startRect, endRect, finalRadius, !mIsOpening));
// Create reveal animator for the folder content (capture the top 4 icons 2x2)
- int width = mDeviceProfile.folderCellLayoutBorderSpacePx.x
+ int width = mDeviceProfile.folderCellLayoutBorderSpacePx
+ mDeviceProfile.folderCellWidthPx * 2;
- int height = mDeviceProfile.folderCellLayoutBorderSpacePx.y
+ int height = mDeviceProfile.folderCellLayoutBorderSpacePx
+ mDeviceProfile.folderCellHeightPx * 2;
int page = mIsOpening ? mContent.getCurrentPage() : mContent.getDestinationPage();
int left = mContent.getPaddingLeft() + page * lp.width;
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 49d27b7..70956a3 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -18,6 +18,7 @@
import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS;
+import static com.android.launcher3.config.FeatureFlags.IS_STUDIO_BUILD;
import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
import android.content.Intent;
@@ -207,7 +208,11 @@
PreferenceScreen screen = getPreferenceScreen();
for (int i = screen.getPreferenceCount() - 1; i >= 0; i--) {
Preference preference = screen.getPreference(i);
- if (!initPreference(preference)) {
+ if (initPreference(preference)) {
+ if (IS_STUDIO_BUILD && preference == mDeveloperOptionPref) {
+ preference.setOrder(0);
+ }
+ } else {
screen.removePreference(preference);
}
}
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index af689dc..78e17d8 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -585,7 +585,6 @@
@Override
public void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect,
SplitBounds splitInfo, int desiredStagePosition) {
- boolean isLandscape = dp.isLandscape;
float topLeftTaskPercent = splitInfo.appsStackedVertically
? splitInfo.topTaskPercent
: splitInfo.leftTaskPercent;
@@ -593,18 +592,24 @@
? splitInfo.dividerHeightPercent
: splitInfo.dividerWidthPercent;
+ int deviceHeightWithoutTaskbar = dp.availableHeightPx - dp.taskbarSize;
+ float scale = (float) outRect.height() / deviceHeightWithoutTaskbar;
+ float topTaskHeight = dp.availableHeightPx * topLeftTaskPercent;
+ float scaledTopTaskHeight = topTaskHeight * scale;
+ float dividerHeight = dp.availableHeightPx * dividerBarPercent;
+ float scaledDividerHeight = dividerHeight * scale;
+
if (desiredStagePosition == SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT) {
- if (isLandscape) {
- outRect.right = outRect.left + Math.round(outRect.width() * topLeftTaskPercent);
+ if (splitInfo.appsStackedVertically) {
+ outRect.bottom = Math.round(outRect.top + scaledTopTaskHeight);
} else {
- outRect.bottom = outRect.top + Math.round(outRect.height() * topLeftTaskPercent);
+ outRect.right = outRect.left + Math.round(outRect.width() * topLeftTaskPercent);
}
} else {
- if (isLandscape) {
- outRect.left += Math.round(outRect.width()
- * (topLeftTaskPercent + dividerBarPercent));
+ if (splitInfo.appsStackedVertically) {
+ outRect.top += Math.round(scaledTopTaskHeight + scaledDividerHeight);
} else {
- outRect.top += Math.round(outRect.height()
+ outRect.left += Math.round(outRect.width()
* (topLeftTaskPercent + dividerBarPercent));
}
}
@@ -617,7 +622,7 @@
int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
int dividerBar = Math.round(splitBoundsConfig.appsStackedVertically
- ? splitBoundsConfig.dividerHeightPercent * totalThumbnailHeight
+ ? splitBoundsConfig.dividerHeightPercent * dp.availableHeightPx
: splitBoundsConfig.dividerWidthPercent * parentWidth);
int primarySnapshotHeight;
int primarySnapshotWidth;
@@ -641,12 +646,18 @@
}
secondarySnapshot.setTranslationY(spaceAboveSnapshot);
} else {
+ int deviceHeightWithoutTaskbar = dp.availableHeightPx - dp.taskbarSize;
+ float scale = (float) totalThumbnailHeight / deviceHeightWithoutTaskbar;
+ float topTaskHeight = dp.availableHeightPx * taskPercent;
+ float finalDividerHeight = dividerBar * scale;
+ float scaledTopTaskHeight = topTaskHeight * scale;
primarySnapshotWidth = parentWidth;
- primarySnapshotHeight = Math.round(totalThumbnailHeight * taskPercent);
+ primarySnapshotHeight = Math.round(scaledTopTaskHeight);
secondarySnapshotWidth = parentWidth;
- secondarySnapshotHeight = totalThumbnailHeight - primarySnapshotHeight - dividerBar;
- int translationY = primarySnapshotHeight + spaceAboveSnapshot + dividerBar;
+ secondarySnapshotHeight = Math.round(totalThumbnailHeight - primarySnapshotHeight
+ - finalDividerHeight);
+ float translationY = primarySnapshotHeight + spaceAboveSnapshot + finalDividerHeight;
secondarySnapshot.setTranslationY(translationY);
FrameLayout.LayoutParams primaryParams =
diff --git a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
index 2c1cbdf..fe30fdc 100644
--- a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
+++ b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
@@ -16,11 +16,12 @@
package com.android.launcher3
import android.content.Context
+import android.graphics.Point
import android.graphics.PointF
import android.graphics.Rect
import android.util.SparseArray
import androidx.test.core.app.ApplicationProvider
-import com.android.launcher3.DeviceProfile.DEFAULT_PROVIDER;
+import com.android.launcher3.DeviceProfile.DEFAULT_PROVIDER
import com.android.launcher3.util.DisplayController.Info
import com.android.launcher3.util.WindowBounds
import org.junit.Before
@@ -116,10 +117,7 @@
numFolderRows = 3
numFolderColumns = 3
- folderBorderSpaces = PointF(16f, 16f)
- folderTopPadding = 24f
- folderCellSize = PointF(80f, 94f)
-
+ folderStyle = R.style.FolderDefaultStyle
inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_4_5
@@ -207,9 +205,7 @@
numFolderRows = 3
numFolderColumns = 3
- folderBorderSpaces = PointF(16f, 16f)
- folderTopPadding = 24f
- folderCellSize = PointF(120f, 104f)
+ folderStyle = R.style.FolderDefaultStyle
inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_6_5
@@ -241,7 +237,7 @@
numAllAppsColumns = 6
isScalable = true
- devicePaddingId = 2132148242 // "@xml/paddings_6x5"
+ devicePaddingId = R.xml.paddings_6x5
inlineQsb = booleanArrayOf(
false,
@@ -305,9 +301,7 @@
numFolderRows = 3
numFolderColumns = 3
- folderBorderSpaces = PointF(16f, 16f)
- folderTopPadding = 24f
- folderCellSize = PointF(80f, 94f)
+ folderStyle = R.style.FolderDefaultStyle
inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_4_4
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index 15705e7..5a96d95 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -58,7 +58,7 @@
"want to switch from background to overview")) {
verifyActiveContainer();
goToOverviewUnchecked();
- return mLauncher.isFallbackOverview()
+ return mLauncher.is3PLauncher()
? new BaseOverview(mLauncher) : new Overview(mLauncher);
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index 4b02ecc..f23a38c 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -55,7 +55,7 @@
public Taskbar getTaskbar() {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to get the taskbar")) {
- mLauncher.waitForLauncherObject(TASKBAR_RES_ID);
+ mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
return new Taskbar(mLauncher);
}
@@ -67,7 +67,7 @@
public void assertTaskbarHidden() {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"waiting for taskbar to be hidden")) {
- mLauncher.waitUntilLauncherObjectGone(TASKBAR_RES_ID);
+ mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
}
}
@@ -77,7 +77,7 @@
public void assertTaskbarVisible() {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"waiting for taskbar to be visible")) {
- mLauncher.waitForLauncherObject(TASKBAR_RES_ID);
+ mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
}
}
@@ -92,7 +92,7 @@
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"want to show the taskbar")) {
- mLauncher.waitUntilLauncherObjectGone(TASKBAR_RES_ID);
+ mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
final long downTime = SystemClock.uptimeMillis();
final int unstashTargetY = mLauncher.getRealDisplaySize().y
@@ -106,7 +106,7 @@
LauncherInstrumentation.log("showTaskbar: sent down");
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) {
- mLauncher.waitForLauncherObject(TASKBAR_RES_ID);
+ mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, unstashTarget,
LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER);
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index fe060a1..1212c3d 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -561,7 +561,7 @@
private String getVisibleStateMessage() {
if (hasLauncherObject(CONTEXT_MENU_RES_ID)) return "Context Menu";
if (hasLauncherObject(WIDGETS_RES_ID)) return "Widgets";
- if (hasLauncherObject(OVERVIEW_RES_ID)) return "Overview";
+ if (hasSystemLauncherObject(OVERVIEW_RES_ID)) return "Overview";
if (hasLauncherObject(WORKSPACE_RES_ID)) return "Workspace";
if (hasLauncherObject(APPS_RES_ID)) return "AllApps";
return "LaunchedApp (" + getVisiblePackages() + ")";
@@ -773,73 +773,89 @@
switch (containerType) {
case WORKSPACE: {
waitUntilLauncherObjectGone(APPS_RES_ID);
- waitUntilLauncherObjectGone(OVERVIEW_RES_ID);
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
- waitUntilLauncherObjectGone(TASKBAR_RES_ID);
- waitUntilLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
+ waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
+ waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
+
+ if (is3PLauncher() && isTablet()) {
+ waitForSystemLauncherObject(TASKBAR_RES_ID);
+ } else {
+ waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
+ }
return waitForLauncherObject(WORKSPACE_RES_ID);
}
case WIDGETS: {
waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
waitUntilLauncherObjectGone(APPS_RES_ID);
- waitUntilLauncherObjectGone(OVERVIEW_RES_ID);
- waitUntilLauncherObjectGone(TASKBAR_RES_ID);
- waitUntilLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
+ waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
+ waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
+
+ if (is3PLauncher() && isTablet()) {
+ waitForSystemLauncherObject(TASKBAR_RES_ID);
+ } else {
+ waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
+ }
return waitForLauncherObject(WIDGETS_RES_ID);
}
- case TASKBAR_ALL_APPS:
- case HOME_ALL_APPS: {
+ case TASKBAR_ALL_APPS: {
waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
- waitUntilLauncherObjectGone(OVERVIEW_RES_ID);
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
- waitUntilLauncherObjectGone(TASKBAR_RES_ID);
- waitUntilLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
+ waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
+ waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
+ waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
return waitForLauncherObject(APPS_RES_ID);
}
- case OVERVIEW: {
+ case HOME_ALL_APPS: {
+ waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
+ waitUntilLauncherObjectGone(WIDGETS_RES_ID);
+ waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
+ waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
+
+ if (is3PLauncher() && isTablet()) {
+ waitForSystemLauncherObject(TASKBAR_RES_ID);
+ } else {
+ waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
+ }
+
+ return waitForLauncherObject(APPS_RES_ID);
+ }
+ case OVERVIEW:
+ case FALLBACK_OVERVIEW: {
waitUntilLauncherObjectGone(APPS_RES_ID);
waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
- waitUntilLauncherObjectGone(TASKBAR_RES_ID);
- waitUntilLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
+ waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
+ waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
- return waitForLauncherObject(OVERVIEW_RES_ID);
+ return waitForSystemLauncherObject(OVERVIEW_RES_ID);
}
case SPLIT_SCREEN_SELECT: {
waitUntilLauncherObjectGone(APPS_RES_ID);
waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
- waitUntilLauncherObjectGone(TASKBAR_RES_ID);
+ waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
- waitForLauncherObject(SPLIT_PLACEHOLDER_RES_ID);
- return waitForLauncherObject(OVERVIEW_RES_ID);
- }
- case FALLBACK_OVERVIEW: {
- waitUntilLauncherObjectGone(APPS_RES_ID);
- waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
- waitUntilLauncherObjectGone(WIDGETS_RES_ID);
- waitUntilLauncherObjectGone(TASKBAR_RES_ID);
- waitUntilLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
-
- return waitForFallbackLauncherObject(OVERVIEW_RES_ID);
+ waitForSystemLauncherObject(SPLIT_PLACEHOLDER_RES_ID);
+ return waitForSystemLauncherObject(OVERVIEW_RES_ID);
}
case LAUNCHED_APP: {
waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
waitUntilLauncherObjectGone(APPS_RES_ID);
- waitUntilLauncherObjectGone(OVERVIEW_RES_ID);
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
- waitUntilLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
+ waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
+ waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
if (mIgnoreTaskbarVisibility) {
return null;
}
- if (isTablet() && !isFallbackOverview()) {
- waitForLauncherObject(TASKBAR_RES_ID);
+
+ if (isTablet()) {
+ waitForSystemLauncherObject(TASKBAR_RES_ID);
} else {
- waitUntilLauncherObjectGone(TASKBAR_RES_ID);
+ waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
}
return null;
}
@@ -974,14 +990,9 @@
checkForAnomaly(false, true);
final Point displaySize = getRealDisplaySize();
- // The swipe up to home gesture starts from inside the launcher when the user is
- // already home. Otherwise, the gesture can start inside the launcher process if the
- // taskbar is visible.
- boolean gestureStartFromLauncher = isTablet()
- ? !isLauncher3()
- || hasLauncherObject(WORKSPACE_RES_ID)
- || hasLauncherObject(TASKBAR_RES_ID)
- : isLauncherVisible();
+
+ boolean gestureStartFromLauncher =
+ isTablet() ? !isLauncher3() : isLauncherVisible();
// CLose floating views before going back to home.
swipeUpToCloseFloatingView(gestureStartFromLauncher);
@@ -1014,7 +1025,7 @@
NORMAL_STATE_ORDINAL,
!hasLauncherObject(WORKSPACE_RES_ID)
&& (hasLauncherObject(APPS_RES_ID)
- || hasLauncherObject(OVERVIEW_RES_ID)),
+ || hasSystemLauncherObject(OVERVIEW_RES_ID)),
action);
}
try (LauncherInstrumentation.Closable c1 = addContextLayer(
@@ -1070,7 +1081,8 @@
boolean isLauncherContainerVisible() {
final String[] containerResources = {WORKSPACE_RES_ID, OVERVIEW_RES_ID, APPS_RES_ID};
- return Arrays.stream(containerResources).anyMatch(r -> hasLauncherObject(r));
+ return Arrays.stream(containerResources).anyMatch(
+ r -> r.equals(OVERVIEW_RES_ID) ? hasSystemLauncherObject(r) : hasLauncherObject(r));
}
/**
@@ -1153,6 +1165,14 @@
waitUntilGoneBySelector(getOverviewObjectSelector(resId));
}
+ void waitUntilSystemLauncherObjectGone(String resId) {
+ if (is3PLauncher()) {
+ waitUntilOverviewObjectGone(resId);
+ } else {
+ waitUntilLauncherObjectGone(resId);
+ }
+ }
+
void waitUntilLauncherObjectGone(BySelector selector) {
waitUntilGoneBySelector(makeLauncherSelector(selector));
}
@@ -1283,6 +1303,11 @@
return mDevice.hasObject(getLauncherObjectSelector(resId));
}
+ private boolean hasSystemLauncherObject(String resId) {
+ return mDevice.hasObject(is3PLauncher() ? getOverviewObjectSelector(resId)
+ : getLauncherObjectSelector(resId));
+ }
+
boolean hasLauncherObject(BySelector selector) {
return mDevice.hasObject(makeLauncherSelector(selector));
}
@@ -1302,6 +1327,12 @@
}
@NonNull
+ UiObject2 waitForSystemLauncherObject(String resName) {
+ return is3PLauncher() ? waitForOverviewObject(resName)
+ : waitForLauncherObject(resName);
+ }
+
+ @NonNull
UiObject2 waitForLauncherObject(BySelector selector) {
return waitForObjectBySelector(makeLauncherSelector(selector));
}
@@ -1312,11 +1343,6 @@
}
@NonNull
- UiObject2 waitForFallbackLauncherObject(String resName) {
- return waitForObjectBySelector(getOverviewObjectSelector(resName));
- }
-
- @NonNull
UiObject2 waitForAndroidObject(String resId) {
final UiObject2 object = TestHelpers.wait(
Until.findObject(By.res(ANDROID_PACKAGE, resId)), WAIT_TIME_MS);
@@ -1353,7 +1379,7 @@
return mDevice.getLauncherPackageName();
}
- boolean isFallbackOverview() {
+ boolean is3PLauncher() {
return !getOverviewPackageName().equals(getLauncherPackageName());
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Taskbar.java b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
index 0f9d5f5..6ca7f4b 100644
--- a/tests/tapl/com/android/launcher3/tapl/Taskbar.java
+++ b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
@@ -52,7 +52,7 @@
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to get a taskbar icon")) {
return new TaskbarAppIcon(mLauncher, mLauncher.waitForObjectInContainer(
- mLauncher.waitForLauncherObject(TASKBAR_RES_ID),
+ mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID),
AppIcon.getAppIconSelector(appName, mLauncher)));
}
}
@@ -68,7 +68,7 @@
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to hide the taskbar");
LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
- mLauncher.waitForLauncherObject(TASKBAR_RES_ID);
+ mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
final long downTime = SystemClock.uptimeMillis();
Point stashTarget = new Point(
@@ -79,7 +79,7 @@
LauncherInstrumentation.log("hideTaskbar: sent down");
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) {
- mLauncher.waitUntilLauncherObjectGone("taskbar_view");
+ mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, stashTarget,
LauncherInstrumentation.GestureScope.INSIDE);
}
@@ -97,7 +97,8 @@
LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
mLauncher.clickLauncherObject(mLauncher.waitForObjectInContainer(
- mLauncher.waitForLauncherObject(TASKBAR_RES_ID), getAllAppsButtonSelector()));
+ mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID),
+ getAllAppsButtonSelector()));
return new AllAppsFromTaskbar(mLauncher);
}
@@ -108,7 +109,7 @@
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to get all taskbar icons")) {
return mLauncher.waitForObjectsInContainer(
- mLauncher.waitForLauncherObject(TASKBAR_RES_ID),
+ mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID),
AppIcon.getAnyAppIconSelector())
.stream()
.map(UiObject2::getText)