Merge "Desktop tile that is a snapshot of desktop" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
24dd3f57b2
@@ -0,0 +1,46 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<com.android.quickstep.views.DesktopTaskView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="true"
|
||||
android:clipToOutline="true"
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
android:focusable="true">
|
||||
|
||||
<!--
|
||||
TODO(b249371338): DesktopTaskView extends from TaskView. TaskView expects TaskThumbnailView
|
||||
and IconView with these ids to be present. Need to refactor RecentsView to accept child
|
||||
views that do not inherint from TaskView only or create a generic TaskView that have
|
||||
N number of tasks.
|
||||
-->
|
||||
<com.android.quickstep.views.TaskThumbnailView
|
||||
android:id="@+id/snapshot"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.android.quickstep.views.IconView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:focusable="false"
|
||||
android:importantForAccessibility="no"
|
||||
android:visibility="gone" />
|
||||
|
||||
</com.android.quickstep.views.DesktopTaskView>
|
||||
@@ -1882,6 +1882,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
|
||||
}
|
||||
|
||||
private void finishCurrentTransitionToRecents() {
|
||||
// TODO(b/245569277#comment2): enable once isFreeformActive is implemented
|
||||
mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
|
||||
if (mRecentsAnimationController != null) {
|
||||
mRecentsAnimationController.detachNavigationBarFromApp(true);
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.quickstep.views.DesktopTaskView.DESKTOP_MODE_SUPPORTED;
|
||||
import static com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager;
|
||||
@@ -30,6 +32,7 @@ import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.launcher3.util.LooperExecutor;
|
||||
import com.android.launcher3.util.SplitConfigurationOptions;
|
||||
import com.android.quickstep.util.DesktopTask;
|
||||
import com.android.quickstep.util.GroupTask;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.wm.shell.recents.IRecentTasksListener;
|
||||
@@ -253,8 +256,9 @@ public class RecentTasksList {
|
||||
};
|
||||
|
||||
TaskLoadResult allTasks = new TaskLoadResult(requestId, loadKeysOnly, rawTasks.size());
|
||||
|
||||
for (GroupedRecentTaskInfo rawTask : rawTasks) {
|
||||
if (rawTask.getType() == GroupedRecentTaskInfo.TYPE_FREEFORM) {
|
||||
if (DESKTOP_MODE_SUPPORTED && rawTask.getType() == TYPE_FREEFORM) {
|
||||
GroupTask desktopTask = createDesktopTask(rawTask);
|
||||
allTasks.add(desktopTask);
|
||||
continue;
|
||||
@@ -284,14 +288,18 @@ public class RecentTasksList {
|
||||
return allTasks;
|
||||
}
|
||||
|
||||
private GroupTask createDesktopTask(GroupedRecentTaskInfo taskInfo) {
|
||||
// TODO(b/244348395): create a subclass of GroupTask for desktop tile
|
||||
// We need a single task information as the primary task. Use the first task
|
||||
Task.TaskKey key = new Task.TaskKey(taskInfo.getTaskInfo1());
|
||||
Task task = new Task(key);
|
||||
task.desktopTile = true;
|
||||
task.topActivity = key.sourceComponent;
|
||||
return new GroupTask(task, null, null);
|
||||
private DesktopTask createDesktopTask(GroupedRecentTaskInfo recentTaskInfo) {
|
||||
ArrayList<Task> tasks = new ArrayList<>(recentTaskInfo.getTaskInfoList().size());
|
||||
for (ActivityManager.RecentTaskInfo taskInfo : recentTaskInfo.getTaskInfoList()) {
|
||||
Task.TaskKey key = new Task.TaskKey(taskInfo);
|
||||
Task task = Task.from(key, taskInfo, false);
|
||||
task.setLastSnapshotData(taskInfo);
|
||||
task.positionInParent = taskInfo.positionInParent;
|
||||
task.appBounds = taskInfo.configuration.windowConfiguration.getAppBounds();
|
||||
// TODO(b/244348395): tasks should be sorted from oldest to most recently used
|
||||
tasks.add(task);
|
||||
}
|
||||
return new DesktopTask(tasks);
|
||||
}
|
||||
|
||||
private SplitConfigurationOptions.SplitBounds convertSplitBounds(
|
||||
@@ -306,7 +314,7 @@ public class RecentTasksList {
|
||||
private ArrayList<GroupTask> copyOf(ArrayList<GroupTask> tasks) {
|
||||
ArrayList<GroupTask> newTasks = new ArrayList<>();
|
||||
for (int i = 0; i < tasks.size(); i++) {
|
||||
newTasks.add(new GroupTask(tasks.get(i)));
|
||||
newTasks.add(tasks.get(i).copy());
|
||||
}
|
||||
return newTasks;
|
||||
}
|
||||
|
||||
@@ -302,9 +302,15 @@ public final class TaskViewUtils {
|
||||
// to follow the TaskViewSimulator. So the final matrix applied on the thumbnailView is:
|
||||
// Mt K(0)` K(t) Mt`
|
||||
TaskThumbnailView[] thumbnails = v.getThumbnails();
|
||||
Matrix[] mt = new Matrix[simulatorCopies.length];
|
||||
Matrix[] mti = new Matrix[simulatorCopies.length];
|
||||
for (int i = 0; i < thumbnails.length; i++) {
|
||||
|
||||
// In case simulator copies and thumbnail size do no match, ensure we get the lesser.
|
||||
// This ensures we do not create arrays with empty elements or attempt to references
|
||||
// indexes out of array bounds.
|
||||
final int matrixSize = Math.min(simulatorCopies.length, thumbnails.length);
|
||||
|
||||
Matrix[] mt = new Matrix[matrixSize];
|
||||
Matrix[] mti = new Matrix[matrixSize];
|
||||
for (int i = 0; i < matrixSize; i++) {
|
||||
TaskThumbnailView ttv = thumbnails[i];
|
||||
RectF localBounds = new RectF(0, 0, ttv.getWidth(), ttv.getHeight());
|
||||
float[] tvBoundsMapped = new float[]{0, 0, ttv.getWidth(), ttv.getHeight()};
|
||||
@@ -321,14 +327,14 @@ public final class TaskViewUtils {
|
||||
mti[i] = localMti;
|
||||
}
|
||||
|
||||
Matrix[] k0i = new Matrix[simulatorCopies.length];
|
||||
for (int i = 0; i < simulatorCopies.length; i++) {
|
||||
Matrix[] k0i = new Matrix[matrixSize];
|
||||
for (int i = 0; i < matrixSize; i++) {
|
||||
k0i[i] = new Matrix();
|
||||
simulatorCopies[i].getTaskViewSimulator().getCurrentMatrix().invert(k0i[i]);
|
||||
}
|
||||
Matrix animationMatrix = new Matrix();
|
||||
out.addOnFrameCallback(() -> {
|
||||
for (int i = 0; i < simulatorCopies.length; i++) {
|
||||
for (int i = 0; i < matrixSize; i++) {
|
||||
animationMatrix.set(mt[i]);
|
||||
animationMatrix.postConcat(k0i[i]);
|
||||
animationMatrix.postConcat(simulatorCopies[i]
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.quickstep.util;
|
||||
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A {@link Task} container that can contain N number of tasks that are part of the desktop in
|
||||
* recent tasks list.
|
||||
*/
|
||||
public class DesktopTask extends GroupTask {
|
||||
|
||||
public ArrayList<Task> tasks;
|
||||
|
||||
public DesktopTask(ArrayList<Task> tasks) {
|
||||
super(tasks.get(0), null, null, TaskView.Type.DESKTOP);
|
||||
this.tasks = tasks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsTask(int taskId) {
|
||||
for (Task task : tasks) {
|
||||
if (task.key.id == taskId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMultipleTasks() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DesktopTask copy() {
|
||||
return new DesktopTask(tasks);
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
||||
/**
|
||||
@@ -27,24 +28,25 @@ import com.android.systemui.shared.recents.model.Task;
|
||||
* are represented as an app-pair in the recents task list.
|
||||
*/
|
||||
public class GroupTask {
|
||||
public @NonNull Task task1;
|
||||
public @Nullable Task task2;
|
||||
public @Nullable
|
||||
SplitBounds mSplitBounds;
|
||||
@NonNull
|
||||
public final Task task1;
|
||||
@Nullable
|
||||
public final Task task2;
|
||||
@Nullable
|
||||
public final SplitBounds mSplitBounds;
|
||||
@TaskView.Type
|
||||
public final int taskViewType;
|
||||
|
||||
public GroupTask(@NonNull Task t1, @Nullable Task t2,
|
||||
@Nullable SplitBounds splitBounds) {
|
||||
public GroupTask(@NonNull Task t1, @Nullable Task t2, @Nullable SplitBounds splitBounds) {
|
||||
this(t1, t2, splitBounds, t2 != null ? TaskView.Type.GROUPED : TaskView.Type.SINGLE);
|
||||
}
|
||||
|
||||
protected GroupTask(@NonNull Task t1, @Nullable Task t2, @Nullable SplitBounds splitBounds,
|
||||
@TaskView.Type int taskViewType) {
|
||||
task1 = t1;
|
||||
task2 = t2;
|
||||
mSplitBounds = splitBounds;
|
||||
}
|
||||
|
||||
public GroupTask(@NonNull GroupTask group) {
|
||||
task1 = new Task(group.task1);
|
||||
task2 = group.task2 != null
|
||||
? new Task(group.task2)
|
||||
: null;
|
||||
mSplitBounds = group.mSplitBounds;
|
||||
this.taskViewType = taskViewType;
|
||||
}
|
||||
|
||||
public boolean containsTask(int taskId) {
|
||||
@@ -54,4 +56,14 @@ public class GroupTask {
|
||||
public boolean hasMultipleTasks() {
|
||||
return task2 != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this instance
|
||||
*/
|
||||
public GroupTask copy() {
|
||||
return new GroupTask(
|
||||
new Task(task1),
|
||||
task2 != null ? new Task(task2) : null,
|
||||
mSplitBounds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,467 @@
|
||||
/*
|
||||
* 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.quickstep.views;
|
||||
|
||||
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
|
||||
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.ShapeDrawable;
|
||||
import android.graphics.drawable.shapes.RoundRectShape;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.util.RunnableList;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.TaskThumbnailCache;
|
||||
import com.android.quickstep.util.CancellableTask;
|
||||
import com.android.quickstep.util.RecentsOrientedState;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* TaskView that contains all tasks that are part of the desktop.
|
||||
*/
|
||||
// TODO(b/249371338): TaskView needs to be refactored to have better support for N tasks.
|
||||
public class DesktopTaskView extends TaskView {
|
||||
|
||||
/** Flag to indicate whether desktop mode is available on the device */
|
||||
public static final boolean DESKTOP_MODE_SUPPORTED = SystemProperties.getBoolean(
|
||||
"persist.wm.debug.desktop_mode", false);
|
||||
|
||||
private static final String TAG = DesktopTaskView.class.getSimpleName();
|
||||
|
||||
private static final boolean DEBUG = true;
|
||||
|
||||
private List<Task> mTasks;
|
||||
|
||||
private final ArrayList<TaskThumbnailView> mSnapshotViews = new ArrayList<>();
|
||||
|
||||
/** Maps {@code taskIds} to corresponding {@link TaskThumbnailView}s */
|
||||
private final SparseArray<TaskThumbnailView> mSnapshotViewMap = new SparseArray<>();
|
||||
|
||||
private final ArrayList<CancellableTask<?>> mPendingThumbnailRequests = new ArrayList<>();
|
||||
|
||||
public DesktopTaskView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public DesktopTaskView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public DesktopTaskView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
float[] outerRadii = new float[8];
|
||||
Arrays.fill(outerRadii, getTaskCornerRadius());
|
||||
RoundRectShape shape = new RoundRectShape(outerRadii, null, null);
|
||||
ShapeDrawable background = new ShapeDrawable(shape);
|
||||
background.setTint(getResources().getColor(android.R.color.system_neutral2_300));
|
||||
// TODO(b/244348395): this should be wallpaper
|
||||
setBackground(background);
|
||||
|
||||
mSnapshotViews.add(mSnapshotView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(Task task, RecentsOrientedState orientedState) {
|
||||
bind(Collections.singletonList(task), orientedState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this desktop task to the gives task list defined in {@code tasks}
|
||||
*/
|
||||
public void bind(List<Task> tasks, RecentsOrientedState orientedState) {
|
||||
if (DEBUG) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("bind tasks=").append(tasks.size()).append("\n");
|
||||
for (Task task : tasks) {
|
||||
sb.append(" key=").append(task.key).append("\n");
|
||||
}
|
||||
Log.d(TAG, sb.toString());
|
||||
}
|
||||
if (tasks.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
cancelPendingLoadTasks();
|
||||
|
||||
mTasks = tasks;
|
||||
mSnapshotViewMap.clear();
|
||||
|
||||
// Ensure there are equal number of snapshot views and tasks.
|
||||
// More tasks than views, add views. More views than tasks, remove views.
|
||||
// TODO(b/251586230): use a ViewPool for creating TaskThumbnailViews
|
||||
if (mSnapshotViews.size() > mTasks.size()) {
|
||||
int diff = mSnapshotViews.size() - mTasks.size();
|
||||
for (int i = 0; i < diff; i++) {
|
||||
TaskThumbnailView snapshotView = mSnapshotViews.remove(0);
|
||||
removeView(snapshotView);
|
||||
}
|
||||
} else if (mSnapshotViews.size() < mTasks.size()) {
|
||||
int diff = mTasks.size() - mSnapshotViews.size();
|
||||
for (int i = 0; i < diff; i++) {
|
||||
TaskThumbnailView snapshotView = new TaskThumbnailView(getContext());
|
||||
mSnapshotViews.add(snapshotView);
|
||||
addView(snapshotView, new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < mTasks.size(); i++) {
|
||||
Task task = mTasks.get(i);
|
||||
TaskThumbnailView snapshotView = mSnapshotViews.get(i);
|
||||
snapshotView.bind(task);
|
||||
mSnapshotViewMap.put(task.key.id, snapshotView);
|
||||
}
|
||||
|
||||
updateTaskIdContainer();
|
||||
updateTaskIdAttributeContainer();
|
||||
|
||||
setOrientationState(orientedState);
|
||||
}
|
||||
|
||||
private void updateTaskIdContainer() {
|
||||
// TODO(b/249371338): TaskView expects the array to have at least 2 elements.
|
||||
// At least 2 elements in the array
|
||||
mTaskIdContainer = new int[Math.max(mTasks.size(), 2)];
|
||||
for (int i = 0; i < mTasks.size(); i++) {
|
||||
mTaskIdContainer[i] = mTasks.get(i).key.id;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTaskIdAttributeContainer() {
|
||||
// TODO(b/249371338): TaskView expects the array to have at least 2 elements.
|
||||
// At least 2 elements in the array
|
||||
mTaskIdAttributeContainer = new TaskIdAttributeContainer[Math.max(mTasks.size(), 2)];
|
||||
for (int i = 0; i < mTasks.size(); i++) {
|
||||
Task task = mTasks.get(i);
|
||||
TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
|
||||
mTaskIdAttributeContainer[i] = createAttributeContainer(task, thumbnailView);
|
||||
}
|
||||
}
|
||||
|
||||
private TaskIdAttributeContainer createAttributeContainer(Task task,
|
||||
TaskThumbnailView thumbnailView) {
|
||||
return new TaskIdAttributeContainer(task, thumbnailView, null, STAGE_POSITION_UNDEFINED);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Task getTask() {
|
||||
// TODO(b/249371338): returning first task. This won't work well with multiple tasks.
|
||||
return mTasks.size() > 0 ? mTasks.get(0) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskThumbnailView getThumbnail() {
|
||||
// TODO(b/249371338): returning single thumbnail. This won't work well with multiple tasks.
|
||||
Task task = getTask();
|
||||
if (task != null) {
|
||||
return mSnapshotViewMap.get(task.key.id);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsTaskId(int taskId) {
|
||||
// Thumbnail map contains taskId -> thumbnail map. Use the keys for contains
|
||||
return mSnapshotViewMap.contains(taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskListVisibilityChanged(boolean visible, int changes) {
|
||||
cancelPendingLoadTasks();
|
||||
if (visible) {
|
||||
RecentsModel model = RecentsModel.INSTANCE.get(getContext());
|
||||
TaskThumbnailCache thumbnailCache = model.getThumbnailCache();
|
||||
|
||||
if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
|
||||
for (Task task : mTasks) {
|
||||
CancellableTask<?> thumbLoadRequest =
|
||||
thumbnailCache.updateThumbnailInBackground(task, thumbnailData -> {
|
||||
TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
|
||||
if (thumbnailView != null) {
|
||||
thumbnailView.setThumbnail(task, thumbnailData);
|
||||
}
|
||||
});
|
||||
if (thumbLoadRequest != null) {
|
||||
mPendingThumbnailRequests.add(thumbLoadRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
|
||||
for (Task task : mTasks) {
|
||||
TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
|
||||
if (thumbnailView != null) {
|
||||
thumbnailView.setThumbnail(null, null);
|
||||
}
|
||||
// Reset the task thumbnail ref
|
||||
task.thumbnail = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrientationState(RecentsOrientedState orientationState) {
|
||||
// TODO(b/249371338): this copies logic from TaskView
|
||||
PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
|
||||
boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
|
||||
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
|
||||
|
||||
LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
|
||||
|
||||
int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
|
||||
int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
|
||||
int taskMargin = deviceProfile.overviewTaskMarginPx;
|
||||
|
||||
orientationHandler.setTaskIconParams(iconParams, taskMargin, taskIconHeight,
|
||||
thumbnailTopMargin, isRtl);
|
||||
|
||||
LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
|
||||
snapshotParams.topMargin = thumbnailTopMargin;
|
||||
|
||||
for (int i = 0; i < mSnapshotViewMap.size(); i++) {
|
||||
TaskThumbnailView thumbnailView = mSnapshotViewMap.valueAt(i);
|
||||
thumbnailView.setLayoutParams(snapshotParams);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancelPendingLoadTasks() {
|
||||
for (CancellableTask<?> cancellableTask : mPendingThumbnailRequests) {
|
||||
cancellableTask.cancel();
|
||||
}
|
||||
mPendingThumbnailRequests.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offerTouchToChildren(MotionEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean showTaskMenuWithContainer(IconView iconView) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public RunnableList launchTaskAnimated() {
|
||||
RunnableList endCallback = new RunnableList();
|
||||
SystemUiProxy.INSTANCE.get(getContext()).showDesktopApps();
|
||||
RecentsView<?, ?> recentsView = getRecentsView();
|
||||
recentsView.addSideTaskLaunchCallback(endCallback);
|
||||
return endCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launchTask(@NonNull Consumer<Boolean> callback, boolean freezeTaskList) {
|
||||
SystemUiProxy.INSTANCE.get(getContext()).showDesktopApps();
|
||||
callback.accept(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
|
||||
// Sets new thumbnails based on the incoming data and refreshes the rest.
|
||||
// Create a copy of the thumbnail map, so we can track thumbnails that need refreshing.
|
||||
SparseArray<TaskThumbnailView> thumbnailsToRefresh = mSnapshotViewMap.clone();
|
||||
if (thumbnailDatas != null) {
|
||||
for (Task task : mTasks) {
|
||||
int key = task.key.id;
|
||||
TaskThumbnailView thumbnailView = thumbnailsToRefresh.get(key);
|
||||
ThumbnailData thumbnailData = thumbnailDatas.get(key);
|
||||
if (thumbnailView != null && thumbnailData != null) {
|
||||
thumbnailView.setThumbnail(task, thumbnailData);
|
||||
// Remove this thumbnail from the list that should be refreshed.
|
||||
thumbnailsToRefresh.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh the rest that were not updated.
|
||||
for (int i = 0; i < thumbnailsToRefresh.size(); i++) {
|
||||
thumbnailsToRefresh.valueAt(i).refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskThumbnailView[] getThumbnails() {
|
||||
TaskThumbnailView[] thumbnails = new TaskThumbnailView[mSnapshotViewMap.size()];
|
||||
for (int i = 0; i < thumbnails.length; i++) {
|
||||
thumbnails[i] = mSnapshotViewMap.valueAt(i);
|
||||
}
|
||||
return thumbnails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecycle() {
|
||||
resetPersistentViewTransforms();
|
||||
// Clear any references to the thumbnail (it will be re-read either from the cache or the
|
||||
// system on next bind)
|
||||
for (Task task : mTasks) {
|
||||
TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
|
||||
if (thumbnailView != null) {
|
||||
thumbnailView.setThumbnail(task, null);
|
||||
}
|
||||
}
|
||||
setOverlayEnabled(false);
|
||||
onTaskListVisibilityChanged(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
int containerWidth = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int containerHeight = MeasureSpec.getSize(heightMeasureSpec);
|
||||
|
||||
setMeasuredDimension(containerWidth, containerHeight);
|
||||
|
||||
int thumbnails = mSnapshotViewMap.size();
|
||||
if (thumbnails == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int windowWidth = mActivity.getDeviceProfile().widthPx;
|
||||
int windowHeight = mActivity.getDeviceProfile().heightPx;
|
||||
|
||||
float scaleWidth = containerWidth / (float) windowWidth;
|
||||
float scaleHeight = containerHeight / (float) windowHeight;
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG,
|
||||
"onMeasure: container=[" + containerWidth + "," + containerHeight + "] window=["
|
||||
+ windowWidth + "," + windowHeight + "] scale=[" + scaleWidth + ","
|
||||
+ scaleHeight + "]");
|
||||
}
|
||||
|
||||
// Desktop tile is a shrunk down version of launcher and freeform task thumbnails.
|
||||
for (int i = 0; i < mTasks.size(); i++) {
|
||||
Task task = mTasks.get(i);
|
||||
Rect taskSize = task.appBounds;
|
||||
if (taskSize == null) {
|
||||
// Default to quarter of the desktop if we did not get app bounds.
|
||||
taskSize = new Rect(0, 0, windowWidth / 4, windowHeight / 4);
|
||||
}
|
||||
|
||||
int thumbWidth = (int) (taskSize.width() * scaleWidth);
|
||||
int thumbHeight = (int) (taskSize.height() * scaleHeight);
|
||||
|
||||
TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id);
|
||||
if (thumbnailView != null) {
|
||||
thumbnailView.measure(MeasureSpec.makeMeasureSpec(thumbWidth, MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(thumbHeight, MeasureSpec.EXACTLY));
|
||||
|
||||
// Position the task to the same position as it would be on the desktop
|
||||
Point positionInParent = task.positionInParent;
|
||||
if (positionInParent == null) {
|
||||
positionInParent = new Point(0, 0);
|
||||
}
|
||||
int taskX = (int) (positionInParent.x * scaleWidth);
|
||||
int taskY = (int) (positionInParent.y * scaleHeight);
|
||||
thumbnailView.setX(taskX);
|
||||
thumbnailView.setY(taskY);
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onMeasure: task=" + task.key + " thumb=[" + thumbWidth + ","
|
||||
+ thumbHeight + "]" + " pos=[" + taskX + "," + taskY + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOverlayEnabled(boolean overlayEnabled) {
|
||||
// Intentional no-op to prevent setting smart actions overlay on thumbnails
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFullscreenProgress(float progress) {
|
||||
// TODO(b/249371338): this copies parent implementation and makes it work for N thumbs
|
||||
progress = Utilities.boundToRange(progress, 0, 1);
|
||||
mFullscreenProgress = progress;
|
||||
for (int i = 0; i < mSnapshotViewMap.size(); i++) {
|
||||
TaskThumbnailView thumbnailView = mSnapshotViewMap.valueAt(i);
|
||||
thumbnailView.getTaskOverlay().setFullscreenProgress(progress);
|
||||
updateSnapshotRadius();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateSnapshotRadius() {
|
||||
for (int i = 0; i < mSnapshotViewMap.size(); i++) {
|
||||
mSnapshotViewMap.valueAt(i).setFullscreenParams(mCurrentFullscreenParams);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setIconAndDimTransitionProgress(float progress, boolean invert) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorTint(float amount, int tintColor) {
|
||||
for (int i = 0; i < mSnapshotViewMap.size(); i++) {
|
||||
mSnapshotViewMap.valueAt(i).setDimAlpha(amount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyThumbnailSplashAlpha() {
|
||||
for (int i = 0; i < mSnapshotViewMap.size(); i++) {
|
||||
mSnapshotViewMap.valueAt(i).setSplashAlpha(mTaskThumbnailSplashAlpha);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void setThumbnailVisibility(int visibility) {
|
||||
for (int i = 0; i < mSnapshotViewMap.size(); i++) {
|
||||
mSnapshotViewMap.valueAt(i).setVisibility(visibility);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean confirmSecondSplitSelectApp() {
|
||||
// Desktop tile can't be in split screen
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -224,6 +224,12 @@ public class GroupedTaskView extends TaskView {
|
||||
mSnapshotView2.refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsTaskId(int taskId) {
|
||||
return (mTask != null && mTask.key.id == taskId)
|
||||
|| (mSecondaryTask != null && mSecondaryTask.key.id == taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskThumbnailView[] getThumbnails() {
|
||||
return new TaskThumbnailView[]{mSnapshotView, mSnapshotView2};
|
||||
|
||||
@@ -54,6 +54,7 @@ import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITIO
|
||||
import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
|
||||
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
|
||||
import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA;
|
||||
import static com.android.quickstep.views.DesktopTaskView.DESKTOP_MODE_SUPPORTED;
|
||||
import static com.android.quickstep.views.OverviewActionsView.FLAG_IS_NOT_TABLET;
|
||||
import static com.android.quickstep.views.OverviewActionsView.FLAG_SINGLE_TASK;
|
||||
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NON_ZERO_ROTATION;
|
||||
@@ -72,6 +73,7 @@ import android.animation.PropertyValuesHolder;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.content.Context;
|
||||
import android.content.LocusId;
|
||||
import android.content.res.Configuration;
|
||||
@@ -171,6 +173,7 @@ import com.android.quickstep.ViewUtils;
|
||||
import com.android.quickstep.util.ActiveGestureErrorDetector;
|
||||
import com.android.quickstep.util.ActiveGestureLog;
|
||||
import com.android.quickstep.util.AnimUtils;
|
||||
import com.android.quickstep.util.DesktopTask;
|
||||
import com.android.quickstep.util.GroupTask;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.quickstep.util.RecentsOrientedState;
|
||||
@@ -195,6 +198,7 @@ import com.android.systemui.shared.system.TaskStackChangeListeners;
|
||||
import com.android.wm.shell.pip.IPipAnimationListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -477,10 +481,11 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
private final InvariantDeviceProfile mIdp;
|
||||
|
||||
/**
|
||||
* Getting views should be done via {@link #getTaskViewFromPool(boolean)}
|
||||
* Getting views should be done via {@link #getTaskViewFromPool(int)}
|
||||
*/
|
||||
private final ViewPool<TaskView> mTaskViewPool;
|
||||
private final ViewPool<GroupedTaskView> mGroupedTaskViewPool;
|
||||
private final ViewPool<DesktopTaskView> mDesktopTaskViewPool;
|
||||
|
||||
private final TaskOverlayFactory mTaskOverlayFactory;
|
||||
|
||||
@@ -737,6 +742,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
10 /* initial size */);
|
||||
mGroupedTaskViewPool = new ViewPool<>(context, this,
|
||||
R.layout.task_grouped, 20 /* max size */, 10 /* initial size */);
|
||||
mDesktopTaskViewPool = new ViewPool<>(context, this, R.layout.task_desktop,
|
||||
5 /* max size */, 1 /* initial size */);
|
||||
|
||||
mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
|
||||
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
|
||||
@@ -981,6 +988,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
}
|
||||
if (child instanceof GroupedTaskView) {
|
||||
mGroupedTaskViewPool.recycle((GroupedTaskView) taskView);
|
||||
} else if (child instanceof DesktopTaskView) {
|
||||
mDesktopTaskViewPool.recycle((DesktopTaskView) taskView);
|
||||
} else {
|
||||
mTaskViewPool.recycle(taskView);
|
||||
}
|
||||
@@ -1199,8 +1208,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
|
||||
for (int i = 0; i < getTaskViewCount(); i++) {
|
||||
TaskView taskView = requireTaskViewAt(i);
|
||||
int[] taskIds = taskView.getTaskIds();
|
||||
if (taskIds[0] == taskId || taskIds[1] == taskId) {
|
||||
if (taskView.containsTaskId(taskId)) {
|
||||
return taskView;
|
||||
}
|
||||
}
|
||||
@@ -1481,21 +1489,24 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
// Add views as children based on whether it's grouped or single task
|
||||
for (int i = taskGroups.size() - 1; i >= 0; i--) {
|
||||
GroupTask groupTask = taskGroups.get(i);
|
||||
boolean hasMultipleTasks = groupTask.hasMultipleTasks();
|
||||
TaskView taskView = getTaskViewFromPool(hasMultipleTasks);
|
||||
TaskView taskView = getTaskViewFromPool(groupTask.taskViewType);
|
||||
addView(taskView);
|
||||
|
||||
if (hasMultipleTasks) {
|
||||
if (taskView instanceof GroupedTaskView) {
|
||||
boolean firstTaskIsLeftTopTask =
|
||||
groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id;
|
||||
Task leftTopTask = firstTaskIsLeftTopTask ? groupTask.task1 : groupTask.task2;
|
||||
Task rightBottomTask = firstTaskIsLeftTopTask ? groupTask.task2 : groupTask.task1;
|
||||
((GroupedTaskView) taskView).bind(leftTopTask, rightBottomTask, mOrientationState,
|
||||
groupTask.mSplitBounds);
|
||||
} else if (taskView instanceof DesktopTaskView) {
|
||||
((DesktopTaskView) taskView).bind(((DesktopTask) groupTask).tasks,
|
||||
mOrientationState);
|
||||
} else {
|
||||
taskView.bind(groupTask.task1, mOrientationState);
|
||||
}
|
||||
}
|
||||
|
||||
if (!taskGroups.isEmpty()) {
|
||||
addView(mClearAllButton);
|
||||
}
|
||||
@@ -2123,10 +2134,19 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
* Handle the edge case where Recents could increment task count very high over long
|
||||
* period of device usage. Probably will never happen, but meh.
|
||||
*/
|
||||
private <T extends TaskView> T getTaskViewFromPool(boolean isGrouped) {
|
||||
T taskView = isGrouped ?
|
||||
(T) mGroupedTaskViewPool.getView() :
|
||||
(T) mTaskViewPool.getView();
|
||||
private TaskView getTaskViewFromPool(@TaskView.Type int type) {
|
||||
TaskView taskView;
|
||||
switch (type) {
|
||||
case TaskView.Type.GROUPED:
|
||||
taskView = mGroupedTaskViewPool.getView();
|
||||
break;
|
||||
case TaskView.Type.DESKTOP:
|
||||
taskView = mDesktopTaskViewPool.getView();
|
||||
break;
|
||||
case TaskView.Type.SINGLE:
|
||||
default:
|
||||
taskView = mTaskViewPool.getView();
|
||||
}
|
||||
taskView.setTaskViewId(mTaskViewIdCount);
|
||||
if (mTaskViewIdCount == Integer.MAX_VALUE) {
|
||||
mTaskViewIdCount = 0;
|
||||
@@ -2318,12 +2338,19 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
}
|
||||
int runningTaskViewId = -1;
|
||||
boolean needGroupTaskView = runningTasks.length > 1;
|
||||
boolean needDesktopTask = hasDesktopTask(runningTasks);
|
||||
if (shouldAddStubTaskView(runningTasks)) {
|
||||
boolean wasEmpty = getChildCount() == 0;
|
||||
// Add an empty view for now until the task plan is loaded and applied
|
||||
final TaskView taskView;
|
||||
if (needGroupTaskView) {
|
||||
taskView = getTaskViewFromPool(true);
|
||||
if (needDesktopTask) {
|
||||
taskView = getTaskViewFromPool(TaskView.Type.DESKTOP);
|
||||
mTmpRunningTasks = Arrays.copyOf(runningTasks, runningTasks.length);
|
||||
addView(taskView, 0);
|
||||
((DesktopTaskView) taskView).bind(Arrays.asList(mTmpRunningTasks),
|
||||
mOrientationState);
|
||||
} else if (needGroupTaskView) {
|
||||
taskView = getTaskViewFromPool(TaskView.Type.GROUPED);
|
||||
mTmpRunningTasks = new Task[]{runningTasks[0], runningTasks[1]};
|
||||
addView(taskView, 0);
|
||||
// When we create a placeholder task view mSplitBoundsConfig will be null, but with
|
||||
@@ -2332,7 +2359,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
((GroupedTaskView)taskView).bind(mTmpRunningTasks[0], mTmpRunningTasks[1],
|
||||
mOrientationState, mSplitBoundsConfig);
|
||||
} else {
|
||||
taskView = getTaskViewFromPool(false);
|
||||
taskView = getTaskViewFromPool(TaskView.Type.SINGLE);
|
||||
addView(taskView, 0);
|
||||
// The temporary running task is only used for the duration between the start of the
|
||||
// gesture and the task list is loaded and applied
|
||||
@@ -2367,6 +2394,18 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
reloadIfNeeded();
|
||||
}
|
||||
|
||||
private boolean hasDesktopTask(Task[] runningTasks) {
|
||||
if (!DESKTOP_MODE_SUPPORTED) {
|
||||
return false;
|
||||
}
|
||||
for (Task task : runningTasks) {
|
||||
if (task.key.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the running task id, cleaning up the old running task if necessary.
|
||||
*/
|
||||
|
||||
@@ -86,7 +86,6 @@ import com.android.launcher3.util.ViewPool.Reusable;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.RemoteAnimationTargets;
|
||||
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.TaskIconCache;
|
||||
import com.android.quickstep.TaskOverlayFactory;
|
||||
import com.android.quickstep.TaskThumbnailCache;
|
||||
@@ -135,6 +134,17 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
@IntDef({FLAG_UPDATE_ALL, FLAG_UPDATE_ICON, FLAG_UPDATE_THUMBNAIL})
|
||||
public @interface TaskDataChanges {}
|
||||
|
||||
/**
|
||||
* Type of task view
|
||||
*/
|
||||
@Retention(SOURCE)
|
||||
@IntDef({Type.SINGLE, Type.GROUPED, Type.DESKTOP})
|
||||
public @interface Type {
|
||||
int SINGLE = 1;
|
||||
int GROUPED = 2;
|
||||
int DESKTOP = 3;
|
||||
}
|
||||
|
||||
/** The maximum amount that a task view can be scrimmed, dimmed or tinted. */
|
||||
public static final float MAX_PAGE_SCRIM_ALPHA = 0.4f;
|
||||
|
||||
@@ -331,7 +341,7 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
protected TaskThumbnailView mSnapshotView;
|
||||
protected IconView mIconView;
|
||||
protected final DigitalWellBeingToast mDigitalWellBeingToast;
|
||||
private float mFullscreenProgress;
|
||||
protected float mFullscreenProgress;
|
||||
private float mGridProgress;
|
||||
protected float mTaskThumbnailSplashAlpha;
|
||||
private float mNonGridScale = 1;
|
||||
@@ -373,8 +383,8 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
/**
|
||||
* Index 0 will contain taskID of left/top task, index 1 will contain taskId of bottom/right
|
||||
*/
|
||||
protected final int[] mTaskIdContainer = new int[]{-1, -1};
|
||||
protected final TaskIdAttributeContainer[] mTaskIdAttributeContainer =
|
||||
protected int[] mTaskIdContainer = new int[]{-1, -1};
|
||||
protected TaskIdAttributeContainer[] mTaskIdAttributeContainer =
|
||||
new TaskIdAttributeContainer[2];
|
||||
|
||||
private boolean mShowScreenshot;
|
||||
@@ -524,6 +534,13 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
return mTask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given {@code taskId} is tracked in this view
|
||||
*/
|
||||
public boolean containsTaskId(int taskId) {
|
||||
return mTask != null && mTask.key.id == taskId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer array of two elements to be size consistent with max number of tasks possible
|
||||
* index 0 will contain the taskId, index 1 will be -1 indicating a null taskID value
|
||||
@@ -564,13 +581,13 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
RecentsView recentsView = getRecentsView();
|
||||
if (recentsView == null || mTask == null) {
|
||||
if (recentsView == null || getTask() == null) {
|
||||
return false;
|
||||
}
|
||||
SplitSelectStateController splitSelectStateController =
|
||||
recentsView.getSplitSelectController();
|
||||
if (splitSelectStateController.isSplitSelectActive() &&
|
||||
splitSelectStateController.getInitialTaskId() == mTask.key.id) {
|
||||
splitSelectStateController.getInitialTaskId() == getTask().key.id) {
|
||||
// Prevent taps on the this taskview if it's being animated into split select state
|
||||
return false;
|
||||
}
|
||||
@@ -597,11 +614,14 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
* @return {@code true} if user is already in split select mode and this tap was to choose the
|
||||
* second app. {@code false} otherwise
|
||||
*/
|
||||
private boolean confirmSecondSplitSelectApp() {
|
||||
protected boolean confirmSecondSplitSelectApp() {
|
||||
int index = getLastSelectedChildTaskIndex();
|
||||
TaskIdAttributeContainer container = mTaskIdAttributeContainer[index];
|
||||
return getRecentsView().confirmSplitSelect(this, container.getTask(),
|
||||
container.getIconView(), container.getThumbnailView());
|
||||
if (container != null) {
|
||||
return getRecentsView().confirmSplitSelect(this, container.getTask(),
|
||||
container.getIconView(), container.getThumbnailView());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -707,11 +727,6 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
RecentsView recentsView = getRecentsView();
|
||||
RemoteTargetHandle[] remoteTargetHandles = recentsView.mRemoteTargetHandles;
|
||||
RunnableList runnableList = new RunnableList();
|
||||
if (mTask != null && mTask.desktopTile) {
|
||||
// clicked on desktop
|
||||
SystemUiProxy.INSTANCE.get(getContext()).showDesktopApps();
|
||||
return runnableList;
|
||||
}
|
||||
if (isRunningTask() && remoteTargetHandles != null) {
|
||||
if (!mIsClickableAsLiveTile) {
|
||||
return runnableList;
|
||||
|
||||
@@ -350,9 +350,11 @@ public class ItemInfo {
|
||||
break;
|
||||
case ITEM_TYPE_TASK:
|
||||
itemBuilder
|
||||
.setTask(LauncherAtom.Task.newBuilder()
|
||||
.setComponentName(getTargetComponent().flattenToShortString())
|
||||
.setIndex(screenId));
|
||||
.setTask(nullableComponent
|
||||
.map(component -> LauncherAtom.Task.newBuilder()
|
||||
.setComponentName(component.flattenToShortString())
|
||||
.setIndex(screenId))
|
||||
.orElse(LauncherAtom.Task.newBuilder()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user