diff --git a/Android.bp b/Android.bp
index 13a926bc9e..962f269aed 100644
--- a/Android.bp
+++ b/Android.bp
@@ -190,7 +190,7 @@ android_app {
],
optimize: {
- proguard_flags_files: ["proguard.flags"],
+ proguard_flags_files: [":launcher-proguard-rules"],
// Proguard is disable for testing. Derivarive prjects to keep proguard enabled
enabled: false,
},
@@ -302,7 +302,9 @@ android_app {
static_libs: ["Launcher3QuickStepLib"],
optimize: {
- enabled: false,
+ proguard_flags_files: [":launcher-proguard-rules"],
+ enabled: true,
+ shrink_resources: true,
},
platform_apis: true,
@@ -349,6 +351,7 @@ android_app {
optimize: {
proguard_flags_files: ["proguard.flags"],
enabled: true,
+ shrink_resources: true,
},
privileged: true,
@@ -385,6 +388,7 @@ android_app {
optimize: {
proguard_flags_files: ["proguard.flags"],
enabled: true,
+ shrink_resources: true,
},
privileged: true,
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index cc3b30e9dc..46c1332651 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -28,7 +28,7 @@
launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
-
+
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index 87a0f7073f..708aa3cbd6 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -33,9 +33,9 @@
launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
-
+
-
-
\ No newline at end of file
+ android:layout_height="match_parent">
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/task_thumbnail_deprecated.xml b/quickstep/res/layout/task_thumbnail_deprecated.xml
new file mode 100644
index 0000000000..f1a3d62021
--- /dev/null
+++ b/quickstep/res/layout/task_thumbnail_deprecated.xml
@@ -0,0 +1,20 @@
+
+
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
index 89840866c9..44d8a5c647 100644
--- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -20,6 +20,7 @@ import static android.content.ClipDescription.MIMETYPE_TEXT_INTENT;
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
+import static com.android.launcher3.Flags.enablePredictiveBackGesture;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -33,6 +34,9 @@ import android.util.Log;
import android.view.View;
import android.view.WindowInsetsController;
import android.view.WindowManager;
+import android.window.BackEvent;
+import android.window.OnBackAnimationCallback;
+import android.window.OnBackInvokedDispatcher;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -124,6 +128,8 @@ public class WidgetPickerActivity extends BaseActivity {
/** A set of user ids that should be filtered out from the selected widgets. */
@NonNull
Set mFilteredUserIds = new HashSet<>();
+ @Nullable
+ private WidgetsFullSheet mWidgetSheet;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -148,6 +154,18 @@ public class WidgetPickerActivity extends BaseActivity {
refreshAndBindWidgets();
}
+ @Override
+ protected void registerBackDispatcher() {
+ if (!enablePredictiveBackGesture()) {
+ super.registerBackDispatcher();
+ return;
+ }
+
+ getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+ new BackAnimationCallback());
+ }
+
private void parseIntentExtras() {
mTitle = getIntent().getStringExtra(EXTRA_PICKER_TITLE);
mDescription = getIntent().getStringExtra(EXTRA_PICKER_DESCRIPTION);
@@ -293,12 +311,12 @@ public class WidgetPickerActivity extends BaseActivity {
MAIN_EXECUTOR.execute(() -> mPopupDataProvider.setAllWidgets(widgets));
}
- private void openWidgetsSheet() {
+ private void openWidgetsSheet() {
MAIN_EXECUTOR.execute(() -> {
- WidgetsFullSheet widgetSheet = WidgetsFullSheet.show(this, true);
- widgetSheet.mayUpdateTitleAndDescription(mTitle, mDescription);
- widgetSheet.disableNavBarScrim(true);
- widgetSheet.addOnCloseListener(this::finish);
+ mWidgetSheet = WidgetsFullSheet.show(this, true);
+ mWidgetSheet.mayUpdateTitleAndDescription(mTitle, mDescription);
+ mWidgetSheet.disableNavBarScrim(true);
+ mWidgetSheet.addOnCloseListener(this::finish);
});
}
@@ -317,6 +335,51 @@ public class WidgetPickerActivity extends BaseActivity {
}
}
+ /**
+ * Animation callback for different predictive back animation states for the widget picker.
+ */
+ private class BackAnimationCallback implements OnBackAnimationCallback {
+ @Nullable
+ OnBackAnimationCallback mActiveOnBackAnimationCallback;
+
+ @Override
+ public void onBackStarted(@NonNull BackEvent backEvent) {
+ if (mActiveOnBackAnimationCallback != null) {
+ mActiveOnBackAnimationCallback.onBackCancelled();
+ }
+ if (mWidgetSheet != null) {
+ mActiveOnBackAnimationCallback = mWidgetSheet;
+ mActiveOnBackAnimationCallback.onBackStarted(backEvent);
+ }
+ }
+
+ @Override
+ public void onBackInvoked() {
+ if (mActiveOnBackAnimationCallback == null) {
+ return;
+ }
+ mActiveOnBackAnimationCallback.onBackInvoked();
+ mActiveOnBackAnimationCallback = null;
+ }
+
+ @Override
+ public void onBackProgressed(@NonNull BackEvent backEvent) {
+ if (mActiveOnBackAnimationCallback == null) {
+ return;
+ }
+ mActiveOnBackAnimationCallback.onBackProgressed(backEvent);
+ }
+
+ @Override
+ public void onBackCancelled() {
+ if (mActiveOnBackAnimationCallback == null) {
+ return;
+ }
+ mActiveOnBackAnimationCallback.onBackCancelled();
+ mActiveOnBackAnimationCallback = null;
+ }
+ };
+
private WidgetAcceptabilityVerdict isWidgetAcceptable(WidgetItem widget) {
final AppWidgetProviderInfo info = widget.widgetInfo;
if (info == null) {
diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
index b1d511cfcd..3a8c141ecf 100644
--- a/quickstep/src/com/android/quickstep/BaseContainerInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
@@ -42,6 +42,7 @@ import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.views.ScrimView;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.util.ActivityInitListener;
@@ -51,6 +52,7 @@ import com.android.quickstep.views.RecentsViewContainer;
import com.android.systemui.shared.recents.model.ThumbnailData;
import java.util.HashMap;
+import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -269,8 +271,11 @@ public abstract class BaseContainerInterface windowBounds =
+ displayController.getInfo().getCurrentBounds();
+ Rect deviceRotationInsets = windowBounds != null
+ ? windowBounds.get(orientationHandler.getRotation()).insets
+ : new Rect();
// Obtain the landscape/seascape insets, and rotate it to portrait perspective.
orientationHandler.rotateInsets(deviceRotationInsets, outRect);
// Then combine with portrait's insets to leave space for status bar/nav bar in
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index cd62265751..f902284fcb 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -33,6 +33,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DIALOG_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_PIP_ANIMATING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
@@ -416,7 +417,8 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E
| SYSUI_STATE_QUICK_SETTINGS_EXPANDED
| SYSUI_STATE_MAGNIFICATION_OVERLAP
| SYSUI_STATE_DEVICE_DREAMING
- | SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION;
+ | SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION
+ | SYSUI_STATE_DISABLE_GESTURE_PIP_ANIMATING;
return (gestureDisablingStates & mSystemUiStateFlags) == 0 && homeOrOverviewEnabled;
}
diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java
index b3a9199bf9..1f6c02c7aa 100644
--- a/quickstep/src/com/android/quickstep/TaskIconCache.java
+++ b/quickstep/src/com/android/quickstep/TaskIconCache.java
@@ -33,6 +33,7 @@ import android.os.UserHandle;
import android.text.TextUtils;
import android.util.SparseArray;
+import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import com.android.launcher3.R;
@@ -48,6 +49,7 @@ import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.Preconditions;
+import com.android.quickstep.task.thumbnail.data.TaskIconDataSource;
import com.android.quickstep.util.TaskKeyLruCache;
import com.android.quickstep.util.TaskVisualsChangeListener;
import com.android.systemui.shared.recents.model.Task;
@@ -59,7 +61,7 @@ import java.util.concurrent.Executor;
/**
* Manages the caching of task icons and related data.
*/
-public class TaskIconCache implements DisplayInfoChangeListener {
+public class TaskIconCache implements TaskIconDataSource, DisplayInfoChangeListener {
private final Executor mBgExecutor;
@@ -102,7 +104,8 @@ public class TaskIconCache implements DisplayInfoChangeListener {
* @param callback The callback to receive the task after its data has been populated.
* @return A cancelable handle to the request
*/
- public CancellableTask getIconInBackground(Task task, GetTaskIconCallback callback) {
+ @Override
+ public CancellableTask getIconInBackground(Task task, @NonNull GetTaskIconCallback callback) {
Preconditions.assertUIThread();
if (task.icon != null) {
// Nothing to load, the icon is already loaded
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
index 4d6dfc3982..f73db5a1e9 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -16,7 +16,8 @@
package com.android.quickstep.recents.data
-import com.android.quickstep.TaskIconCache
+import android.graphics.drawable.Drawable
+import com.android.quickstep.task.thumbnail.data.TaskIconDataSource
import com.android.quickstep.task.thumbnail.data.TaskThumbnailDataSource
import com.android.quickstep.util.GroupTask
import com.android.systemui.shared.recents.model.Task
@@ -38,7 +39,7 @@ import kotlinx.coroutines.suspendCancellableCoroutine
class TasksRepository(
private val recentsModel: RecentTasksDataSource,
private val taskThumbnailDataSource: TaskThumbnailDataSource,
- private val taskIconCache: TaskIconCache,
+ private val taskIconDataSource: TaskIconDataSource,
) : RecentTasksRepository {
private val groupedTaskData = MutableStateFlow(emptyList())
private val _taskData =
@@ -46,10 +47,19 @@ class TasksRepository(
private val visibleTaskIds = MutableStateFlow(emptySet())
private val taskData: Flow> =
- combine(_taskData, getThumbnailQueryResults()) { tasks, results ->
+ combine(_taskData, getThumbnailQueryResults(), getIconQueryResults()) {
+ tasks,
+ thumbnailQueryResults,
+ iconQueryResults ->
tasks.forEach { task ->
// Add retrieved thumbnails + remove unnecessary thumbnails
- task.thumbnail = results[task.key.id]
+ task.thumbnail = thumbnailQueryResults[task.key.id]
+
+ // TODO(b/352331675) don't load icons for DesktopTaskView
+ // Add retrieved icons + remove unnecessary icons
+ task.icon = iconQueryResults[task.key.id]?.icon
+ task.titleDescription = iconQueryResults[task.key.id]?.contentDescription
+ task.title = iconQueryResults[task.key.id]?.title
}
tasks
}
@@ -79,7 +89,6 @@ class TasksRepository(
suspendCancellableCoroutine { continuation ->
val cancellableTask =
taskThumbnailDataSource.getThumbnailInBackground(task) {
- task.thumbnail = it
continuation.resume(it)
}
continuation.invokeOnCancellation { cancellableTask?.cancel() }
@@ -109,6 +118,59 @@ class TasksRepository(
}
}
}
+
+ /** Flow wrapper for [TaskThumbnailDataSource.getThumbnailInBackground] api */
+ private fun getIconDataRequest(task: Task): IconDataRequest =
+ flow {
+ emit(task.key.id to task.getTaskIconQueryResponse())
+ val iconDataResponse: TaskIconQueryResponse? =
+ suspendCancellableCoroutine { continuation ->
+ val cancellableTask =
+ taskIconDataSource.getIconInBackground(task) {
+ icon,
+ contentDescription,
+ title ->
+ continuation.resume(
+ TaskIconQueryResponse(icon, contentDescription, title)
+ )
+ }
+ continuation.invokeOnCancellation { cancellableTask?.cancel() }
+ }
+ emit(task.key.id to iconDataResponse)
+ }
+ .distinctUntilChanged()
+
+ private fun getIconQueryResults(): Flow