Snap for 7906314 from 185da72e98 to sc-v2-release

Change-Id: Ib733afec6d3b0eed1a278f34f245cb724f51a7d4
This commit is contained in:
Android Build Coastguard Worker
2021-11-12 00:07:49 +00:00
40 changed files with 547 additions and 250 deletions
+3 -4
View File
@@ -278,16 +278,15 @@ android_library {
srcs: [
":launcher-src-no-build-config",
],
resource_dirs: [
"quickstep/res",
],
resource_dirs: [],
libs: [
"framework-statsd",
],
static_libs: [
"QuickstepResLib",
"SystemUI-statsd",
"SystemUISharedLib",
"Launcher3CommonDepsLib"
"Launcher3CommonDepsLib",
],
manifest: "quickstep/AndroidManifest.xml",
platform_apis: true,
+4 -3
View File
@@ -15,7 +15,8 @@
limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="?android:attr/colorPrimary"/>
<corners android:radius="@dimen/task_menu_item_corner_radius"/>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<solid android:color="?androidprv:attr/colorSurface" />
<corners android:radius="@dimen/task_menu_item_corner_radius" />
</shape>
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.TaskMenuViewWithArrow
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:background="@drawable/task_menu_bg"
android:orientation="vertical"
android:visibility="invisible">
<LinearLayout
android:id="@+id/menu_option_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:showDividers="middle" />
</com.android.quickstep.views.TaskMenuViewWithArrow>
@@ -18,7 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:orientation="horizontal"
android:paddingTop="@dimen/task_card_menu_option_vertical_padding"
android:paddingBottom="@dimen/task_card_menu_option_vertical_padding"
android:background="@drawable/task_menu_item_bg"
+2 -2
View File
@@ -27,7 +27,7 @@
<dimen name="task_menu_corner_radius">22dp</dimen>
<dimen name="task_menu_item_corner_radius">4dp</dimen>
<dimen name="task_menu_spacing">2dp</dimen>
<dimen name="task_menu_width_grid">200dp</dimen>
<dimen name="task_menu_width_grid">234dp</dimen>
<dimen name="overview_proactive_row_height">48dp</dimen>
<dimen name="overview_proactive_row_bottom_margin">16dp</dimen>
@@ -91,7 +91,7 @@
<dimen name="task_menu_vertical_padding">8dp</dimen>
<dimen name="task_card_margin">8dp</dimen>
<dimen name="task_card_menu_shadow_height">3dp</dimen>
<dimen name="task_menu_option_start_margin">12dp</dimen>
<dimen name="task_menu_option_start_margin">16dp</dimen>
<!-- Copied from framework resource:
docked_stack_divider_thickness - 2 * docked_stack_divider_insets -->
<dimen name="multi_window_task_divider_size">10dp</dimen>
@@ -61,7 +61,6 @@ import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.SettingsCache;
@@ -108,6 +107,8 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
private final boolean mIsSafeModeEnabled;
private final boolean mIsUserSetupComplete;
private boolean mIsDestroyed = false;
// The flag to know if the window is excluded from magnification region computation.
private boolean mIsExcludeFromMagnificationRegion = false;
public TaskbarActivityContext(Context windowContext, DeviceProfile dp,
TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
@@ -520,4 +521,25 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
protected boolean isUserSetupComplete() {
return mIsUserSetupComplete;
}
/**
* Called when we determine the touchable region.
*
* @param exclude {@code true} then the magnification region computation will omit the window.
*/
public void excludeFromMagnificationRegion(boolean exclude) {
if (mIsExcludeFromMagnificationRegion == exclude) {
return;
}
mIsExcludeFromMagnificationRegion = exclude;
if (exclude) {
mWindowLayoutParams.privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
} else {
mWindowLayoutParams.privateFlags &=
~WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
}
mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
}
}
@@ -137,12 +137,14 @@ public class TaskbarDragLayerController {
// Always have nav buttons be touchable
mControllers.navbarButtonsViewController.addVisibleButtonsRegion(
mTaskbarDragLayer, insetsInfo.touchableRegion);
boolean insetsIsTouchableRegion = true;
if (mTaskbarDragLayer.getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
// Let touches pass through us.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
} else if (mControllers.navbarButtonsViewController.isImeVisible()) {
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_CONTENT);
insetsIsTouchableRegion = false;
} else if (!mControllers.uiController.isTaskbarTouchable()) {
// Let touches pass through us.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
@@ -151,9 +153,11 @@ public class TaskbarDragLayerController {
// Taskbar has some touchable elements, take over the full taskbar area
insetsInfo.setTouchableInsets(mActivity.isTaskbarWindowFullscreen()
? TOUCHABLE_INSETS_FRAME : TOUCHABLE_INSETS_CONTENT);
insetsIsTouchableRegion = false;
} else {
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
}
mActivity.excludeFromMagnificationRegion(insetsIsTouchableRegion);
}
/**
@@ -122,6 +122,7 @@ import com.android.systemui.shared.system.TaskStackChangeListeners;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Arrays;
import java.util.function.Consumer;
/**
@@ -976,12 +977,13 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
}
/** @return Whether this was the task we were waiting to appear, and thus handled it. */
protected boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
protected boolean handleTaskAppeared(RemoteAnimationTargetCompat[] appearedTaskTarget) {
if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
return false;
}
if (mStateCallback.hasStates(STATE_START_NEW_TASK)
&& appearedTaskTarget.taskId == mGestureState.getLastStartedTaskId()) {
boolean hasStartedTaskBefore = Arrays.stream(appearedTaskTarget).anyMatch(
targetCompat -> targetCompat.taskId == mGestureState.getLastStartedTaskId());
if (mStateCallback.hasStates(STATE_START_NEW_TASK) && hasStartedTaskBefore) {
reset();
return true;
}
@@ -1809,13 +1811,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
mGestureState.updateLastStartedTaskId(taskId);
boolean hasTaskPreviouslyAppeared = mGestureState.getPreviouslyAppearedTaskIds()
.contains(taskId);
boolean isOldTaskSplit = LauncherSplitScreenListener.INSTANCE.getNoCreate()
.getRunningSplitTaskIds().length > 0;
nextTask.launchTask(success -> {
resultCallback.accept(success);
if (isOldTaskSplit) {
SystemUiProxy.INSTANCE.getNoCreate().exitSplitScreen(taskId);
}
if (success) {
if (hasTaskPreviouslyAppeared) {
onRestartPreviouslyAppearedTask();
@@ -1871,9 +1868,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
}
@Override
public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
public void onTasksAppeared(RemoteAnimationTargetCompat[] appearedTaskTargets) {
if (mRecentsAnimationController != null) {
if (handleTaskAppeared(appearedTaskTarget)) {
if (handleTaskAppeared(appearedTaskTargets)) {
mRecentsAnimationController.finish(false /* toRecents */,
null /* onFinishComplete */);
mActivityInterface.onLaunchTaskSuccess();
@@ -147,7 +147,7 @@ public class FallbackSwipeHandler extends
}
@Override
protected boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
protected boolean handleTaskAppeared(RemoteAnimationTargetCompat[] appearedTaskTarget) {
if (mActiveAnimationFactory != null
&& mActiveAnimationFactory.handleHomeTaskAppeared(appearedTaskTarget)) {
mActiveAnimationFactory = null;
@@ -260,7 +260,8 @@ public class FallbackSwipeHandler extends
}
}
public boolean handleHomeTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
public boolean handleHomeTaskAppeared(RemoteAnimationTargetCompat[] appearedTaskTargets) {
RemoteAnimationTargetCompat appearedTaskTarget = appearedTaskTargets[0];
if (appearedTaskTarget.activityType == ACTIVITY_TYPE_HOME) {
RemoteAnimationTargets targets = new RemoteAnimationTargets(
new RemoteAnimationTargetCompat[] {appearedTaskTarget},
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2021 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;
import com.android.launcher3.R;
/**
* Bridge class to allow using resources in Kotlin.
* <br/>
* TODO(b/204069723) Can't use resources directly in Kotlin
*/
public class KtR {
public static final class id {
public static int menu_option_layout = R.id.menu_option_layout;
}
public static final class dimen {
public static int task_menu_spacing = R.dimen.task_menu_spacing;
}
public static final class layout {
public static int task_menu_with_arrow = R.layout.task_menu_with_arrow;
public static int task_view_menu_option = R.layout.task_view_menu_option;
}
}
@@ -27,12 +27,14 @@ import android.util.SparseBooleanArray;
import androidx.annotation.VisibleForTesting;
import com.android.quickstep.util.GroupTask;
import com.android.launcher3.util.LooperExecutor;
import com.android.systemui.shared.recents.model.GroupTask;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.KeyguardManagerCompat;
import com.android.wm.shell.recents.IRecentTasksListener;
import com.android.wm.shell.util.GroupedRecentTaskInfo;
import com.android.wm.shell.util.StagedSplitBounds;
import java.util.ArrayList;
import java.util.Collections;
@@ -192,12 +194,23 @@ public class RecentTasksList {
tmpLockedUsers.get(task2Key.userId) /* isLocked */);
task2.setLastSnapshotData(taskInfo2);
}
allTasks.add(new GroupTask(task1, task2));
final SplitConfigurationOptions.StagedSplitBounds launcherSplitBounds =
convertSplitBounds(rawTask.mStagedSplitBounds);
allTasks.add(new GroupTask(task1, task2, launcherSplitBounds));
}
return allTasks;
}
private SplitConfigurationOptions.StagedSplitBounds convertSplitBounds(
StagedSplitBounds shellSplitBounds) {
return shellSplitBounds == null ?
null :
new SplitConfigurationOptions.StagedSplitBounds(
shellSplitBounds.leftTopBounds, shellSplitBounds.rightBottomBounds,
shellSplitBounds.leftTopTaskId, shellSplitBounds.rightBottomTaskId);
}
private ArrayList<GroupTask> copyOf(ArrayList<GroupTask> tasks) {
ArrayList<GroupTask> newTasks = new ArrayList<>();
for (int i = 0; i < tasks.size(); i++) {
@@ -136,10 +136,10 @@ public class RecentsAnimationCallbacks implements
@BinderThread
@Override
public void onTaskAppeared(RemoteAnimationTargetCompat app) {
public void onTasksAppeared(RemoteAnimationTargetCompat[] apps) {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
for (RecentsAnimationListener listener : getListeners()) {
listener.onTaskAppeared(app);
listener.onTasksAppeared(apps);
}
});
}
@@ -177,6 +177,6 @@ public class RecentsAnimationCallbacks implements
/**
* Callback made when a task started from the recents is ready for an app transition.
*/
default void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {}
default void onTasksAppeared(RemoteAnimationTargetCompat[] appearedTaskTarget) {}
}
}
@@ -34,7 +34,7 @@ import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.icons.IconProvider.IconChangeListener;
import com.android.launcher3.util.Executors.SimpleThreadFactory;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.systemui.shared.recents.model.GroupTask;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -20,7 +20,7 @@ import android.content.Context;
import androidx.annotation.Nullable;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.TaskViewSimulator;
@@ -33,7 +33,7 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
*/
public class RemoteTargetGluer {
private RemoteTargetHandle[] mRemoteTargetHandles;
private SplitConfigurationOptions.StagedSplitBounds mStagedSplitBounds;
private StagedSplitBounds mStagedSplitBounds;
/**
* Use this constructor if remote targets are split-screen independent
@@ -85,13 +85,21 @@ public class RemoteTargetGluer {
/**
* Similar to {@link #assignTargets(RemoteAnimationTargets)}, except this matches the
* apps in targets.apps to that of the split screened tasks. If split screen is active, then
* {@link #mRemoteTargetHandles} index 0 will be the left/top task, index one right/bottom
* apps in targets.apps to that of the _active_ split screened tasks.
* See {@link #assignTargetsForSplitScreen(RemoteAnimationTargets, int[])}
*/
public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets) {
int[] splitIds = LauncherSplitScreenListener.INSTANCE.getNoCreate()
.getRunningSplitTaskIds();
return assignTargetsForSplitScreen(targets, splitIds);
}
/**
* Assigns the provided splitIDs to the {@link #mRemoteTargetHandles}, with index 0 will beint
* the left/top task, index 1 right/bottom
*/
public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets,
int[] splitIds) {
RemoteAnimationTargetCompat primaryTaskTarget;
RemoteAnimationTargetCompat secondaryTaskTarget;
if (mRemoteTargetHandles.length == 1) {
@@ -108,9 +116,9 @@ public class RemoteTargetGluer {
primaryTaskTarget = targets.findTask(splitIds[0]);
secondaryTaskTarget = targets.findTask(splitIds[1]);
mStagedSplitBounds = new SplitConfigurationOptions.StagedSplitBounds(
mStagedSplitBounds = new StagedSplitBounds(
primaryTaskTarget.screenSpaceBounds,
secondaryTaskTarget.screenSpaceBounds);
secondaryTaskTarget.screenSpaceBounds, splitIds[0], splitIds[1]);
mRemoteTargetHandles[0].mTransformParams.setTargetSet(
createRemoteAnimationTargetsForTarget(primaryTaskTarget, targets));
mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(primaryTaskTarget,
@@ -135,7 +143,7 @@ public class RemoteTargetGluer {
return mRemoteTargetHandles;
}
public SplitConfigurationOptions.StagedSplitBounds getStagedSplitBounds() {
public StagedSplitBounds getStagedSplitBounds() {
return mStagedSplitBounds;
}
@@ -572,53 +572,6 @@ public class SystemUiProxy implements ISystemUiProxy,
mPendingSplitScreenListener = null;
}
public void setSideStageVisibility(boolean visible) {
if (mSplitScreen != null) {
try {
mSplitScreen.setSideStageVisibility(visible);
} catch (RemoteException e) {
Log.w(TAG, "Failed call setSideStageVisibility");
}
}
}
/**
* To be called whenever the user exits out of split screen apps (either by launching another
* app or by swiping home)
* @param topTaskId The taskId of the new app that was launched. System will then move this task
* to the front of what the user sees while removing all other split stages.
* If swiping to home (or there is no task to put at the top), can pass in -1.
*/
public void exitSplitScreen(int topTaskId) {
if (mSplitScreen != null) {
try {
mSplitScreen.exitSplitScreen(topTaskId);
} catch (RemoteException e) {
Log.w(TAG, "Failed call exitSplitScreen");
}
}
}
public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
if (mSplitScreen != null) {
try {
mSplitScreen.exitSplitScreenOnHide(exitSplitScreenOnHide);
} catch (RemoteException e) {
Log.w(TAG, "Failed call exitSplitScreen");
}
}
}
public void startTask(int taskId, int stage, int position, Bundle options) {
if (mSplitScreen != null) {
try {
mSplitScreen.startTask(taskId, stage, position, options);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startTask");
}
}
}
/** Start multiple tasks in split-screen simultaneously. */
public void startTasks(int mainTaskId, Bundle mainOptions, int sideTaskId, Bundle sideOptions,
@SplitConfigurationOptions.StagePosition int sidePosition,
@@ -147,16 +147,16 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
}
@Override
public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
public void onTasksAppeared(RemoteAnimationTargetCompat[] appearedTaskTargets) {
RemoteAnimationTargetCompat appearedTaskTarget = appearedTaskTargets[0];
BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityInterface.isInLiveTileMode()
&& activityInterface.getCreatedActivity() != null) {
RecentsView recentsView =
activityInterface.getCreatedActivity().getOverviewPanel();
if (recentsView != null) {
RemoteAnimationTargetCompat[] apps = new RemoteAnimationTargetCompat[1];
apps[0] = appearedTaskTarget;
recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId, apps,
recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId,
appearedTaskTargets,
new RemoteAnimationTargetCompat[0] /* wallpaper */,
new RemoteAnimationTargetCompat[0] /* nonApps */);
return;
@@ -177,8 +177,8 @@ public final class TaskViewUtils {
} else {
RemoteTargetGluer gluer = new RemoteTargetGluer(v.getContext(),
recentsView.getSizeStrategy(), targets);
if (recentsViewHandles != null && recentsViewHandles.length > 1) {
remoteTargetHandles = gluer.assignTargetsForSplitScreen(targets);
if (v.containsMultipleTasks()) {
remoteTargetHandles = gluer.assignTargetsForSplitScreen(targets, v.getTaskIds());
} else {
remoteTargetHandles = gluer.assignTargets(targets);
}
@@ -42,7 +42,7 @@ import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.GroupTask;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
@@ -175,7 +175,7 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsSta
newList.addAll(taskGroups);
newList.add(new GroupTask(
Task.from(new TaskKey(mHomeTaskInfo), mHomeTaskInfo, false),
null));
null, null));
taskGroups = newList;
}
}
@@ -0,0 +1,56 @@
/*
* Copyright (C) 2021 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 androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import com.android.systemui.shared.recents.model.Task;
/**
* A {@link Task} container that can contain one or two tasks, depending on if the two tasks
* are represented as an app-pair in the recents task list.
*/
public class GroupTask {
public @NonNull Task task1;
public @Nullable Task task2;
public @Nullable StagedSplitBounds mStagedSplitBounds;
public GroupTask(@NonNull Task t1, @Nullable Task t2,
@Nullable StagedSplitBounds stagedSplitBounds) {
task1 = t1;
task2 = t2;
mStagedSplitBounds = stagedSplitBounds;
}
public GroupTask(@NonNull GroupTask group) {
task1 = new Task(group.task1);
task2 = group.task2 != null
? new Task(group.task2)
: null;
mStagedSplitBounds = group.mStagedSplitBounds;
}
public boolean containsTask(int taskId) {
return task1.key.id == taskId || (task2 != null && task2.key.id == taskId);
}
public boolean hasMultipleTasks() {
return task2 != null;
}
}
@@ -149,7 +149,6 @@ public class LauncherSplitScreenListener extends ISplitScreenListener.Stub {
return;
}
SystemUiProxy.INSTANCE.getNoCreate().exitSplitScreen(-1);
mPersistentGroupedIds = EMPTY_ARRAY;
}
@@ -56,6 +56,7 @@ public class SplitSelectStateController {
private Task mInitialTask;
private Task mSecondTask;
private Rect mInitialBounds;
private boolean mRecentsAnimationRunning;
public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) {
mHandler = handler;
@@ -113,6 +114,10 @@ public class SplitSelectStateController {
return mStagePosition;
}
public void setRecentsAnimationRunning(boolean running) {
this.mRecentsAnimationRunning = running;
}
/**
* Requires Shell Transitions
*/
@@ -172,7 +177,9 @@ public class SplitSelectStateController {
public void onAnimationCancelled() {
postAsyncCallback(mHandler, () -> {
if (mSuccessCallback != null) {
mSuccessCallback.accept(false);
// Launching legacy tasks while recents animation is running will always cause
// onAnimationCancelled to be called (should be fixed w/ shell transitions?)
mSuccessCallback.accept(mRecentsAnimationRunning);
}
resetState();
});
@@ -187,6 +194,7 @@ public class SplitSelectStateController {
mSecondTask = null;
mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
mInitialBounds = null;
mRecentsAnimationRunning = false;
}
/**
@@ -22,7 +22,6 @@ import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITIO
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import static com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
import static com.android.quickstep.util.RecentsOrientedState.preDisplayRotation;
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_FULLSCREEN;
@@ -41,6 +40,7 @@ import androidx.annotation.NonNull;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.BaseActivityInterface;
@@ -14,6 +14,7 @@ import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import com.android.launcher3.util.TransformingTouchDelegate;
import com.android.quickstep.RecentsModel;
@@ -118,7 +119,11 @@ public class GroupedTaskView extends TaskView {
}
protected boolean showTaskMenuWithContainer(IconView iconView) {
return TaskMenuView.showForTask(mTaskIdAttributeContainer[iconView == mIconView ? 0 : 1]);
if (mActivity.getDeviceProfile().overviewShowAsGrid) {
return TaskMenuViewWithArrow.Companion.showForTask(mTaskIdAttributeContainer[0]);
} else {
return TaskMenuView.showForTask(mTaskIdAttributeContainer[0]);
}
}
public void updateSplitBoundsConfig(StagedSplitBounds stagedSplitBounds) {
@@ -137,8 +137,8 @@ import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.ResourceBasedOverride.Overrides;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TranslateEdgeEffect;
import com.android.launcher3.util.ViewPool;
@@ -157,7 +157,6 @@ import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.ViewUtils;
import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.SplitScreenBounds;
@@ -167,7 +166,7 @@ import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.VibratorWrapper;
import com.android.systemui.plugins.ResourceProvider;
import com.android.systemui.shared.recents.model.GroupTask;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -599,7 +598,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
*/
private TaskView mSplitHiddenTaskView;
private TaskView mSecondSplitHiddenTaskView;
private SplitConfigurationOptions.StagedSplitBounds mSplitBoundsConfig;
private StagedSplitBounds mSplitBoundsConfig;
private final Toast mSplitToast = Toast.makeText(getContext(),
R.string.toast_split_select_app, Toast.LENGTH_SHORT);
private final Toast mSplitUnsupportedToast = Toast.makeText(getContext(),
@@ -665,9 +664,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
mClearAllButton.setOnClickListener(this::dismissAllTasks);
mTaskViewPool = new ViewPool<>(context, this, R.layout.task, 20 /* max size */,
10 /* initial size */);
// There's only one pair of grouped tasks we can envision at the moment
mGroupedTaskViewPool = new ViewPool<>(context, this,
R.layout.task_grouped, 2 /* max size */, 1 /* initial size */);
R.layout.task_grouped, 20 /* max size */, 10 /* initial size */);
mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
@@ -1071,6 +1069,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
}
public TaskView getTaskViewByTaskId(int taskId) {
if (taskId == -1) {
return null;
}
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView taskView = getTaskViewAt(i);
int[] taskIds = taskView.getTaskIds();
@@ -1323,72 +1325,38 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
TaskView ignoreResetTaskView =
mIgnoreResetTaskId == -1 ? null : getTaskViewByTaskId(mIgnoreResetTaskId);
int[] splitTaskIds =
LauncherSplitScreenListener.INSTANCE.getNoCreate().getPersistentSplitIds();
int requiredGroupTaskViews = splitTaskIds.length / 2;
// TODO(b/202740477): Update once grouped tasks are returned
// Subtract half the number of split tasks and not total number because we've already
// added a GroupedTaskView when swipe up gesture happens.
// This will need to change if we start showing GroupedTaskViews during swipe up from home
int requiredTaskViewCount = taskGroups.size() - requiredGroupTaskViews;
if (getTaskViewCount() != requiredTaskViewCount) {
if (indexOfChild(mClearAllButton) != -1) {
removeView(mClearAllButton);
}
for (int i = getTaskViewCount(); i < requiredTaskViewCount; i++) {
addView(getTaskViewFromPool(false));
}
while (getTaskViewCount() > requiredTaskViewCount) {
removeView(getChildAt(getChildCount() - 1));
}
int groupedTaskViewCount = getGroupedTaskViewCount();
while (requiredGroupTaskViews > groupedTaskViewCount) {
// Add to front of list
addView(getTaskViewFromPool(true), 0);
requiredGroupTaskViews--;
}
if (requiredTaskViewCount > 0) {
addView(mClearAllButton);
}
}
// Save running task ID if it exists before rebinding all taskViews, otherwise the task from
// the runningTaskView currently bound could get assigned to another TaskView
// TODO set these type to array and check all taskIDs? Maybe we can get away w/ only one
int runningTaskId = getTaskIdsForTaskViewId(mRunningTaskViewId)[0];
int focusedTaskId = getTaskIdsForTaskViewId(mFocusedTaskViewId)[0];
Log.d(TASK_VIEW_ID_CRASH, "runningTaskId beforeBind: " + runningTaskId
+ " runningTaskViewId: " + mRunningTaskViewId
+ " forTaskView: " + getTaskViewFromTaskViewId(mRunningTaskViewId));
for (int taskViewIndex = requiredTaskViewCount - 1, taskDataIndex = taskGroups.size() - 1;
taskViewIndex >= 0;
taskViewIndex--, taskDataIndex--) {
final int pageIndex = requiredTaskViewCount - taskViewIndex - 1;
// TODO(b/202740477): Temporary assumption, to be updated once groups are actually used
final Task task = taskGroups.get(taskDataIndex).task1;
final TaskView taskView = (TaskView) getChildAt(pageIndex);
if (taskView instanceof GroupedTaskView) {
Task leftTop;
Task rightBottom;
if (task.key.id == splitTaskIds[0]) {
leftTop = task;
taskDataIndex--;
rightBottom = taskGroups.get(taskDataIndex).task1;
} else {
rightBottom = task;
taskDataIndex--;
leftTop = taskGroups.get(taskDataIndex).task1;
}
((GroupedTaskView) taskView).bind(leftTop, rightBottom, mOrientationState,
mSplitBoundsConfig);
// Removing views sets the currentPage to 0, so we save this and restore it after
// the new set of views are added
int previousPage = mCurrentPage;
removeAllViews();
// 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);
addView(taskView);
if (hasMultipleTasks) {
boolean firstTaskIsLeftTopTask =
groupTask.mStagedSplitBounds.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.mStagedSplitBounds);
} else {
taskView.bind(task, mOrientationState);
taskView.bind(groupTask.task1, mOrientationState);
}
}
if (!taskGroups.isEmpty()) {
addView(mClearAllButton);
}
setCurrentPage(previousPage);
// Keep same previous focused task
TaskView newFocusedTaskView = getTaskViewByTaskId(focusedTaskId);
@@ -1406,21 +1374,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
// Update mRunningTaskViewId to be the new TaskView that was assigned by binding
// the full list of tasks to taskViews
newRunningTaskView = getTaskViewByTaskId(runningTaskId);
if (newRunningTaskView == null) {
StringBuilder sb = new StringBuilder();
for (int i = requiredTaskViewCount - 1; i >= 0; i--) {
final int pageIndex = requiredTaskViewCount - i - 1;
final TaskView taskView = (TaskView) getChildAt(pageIndex);
int taskViewId = taskView.getTaskViewId();
sb.append(" taskViewId: " + taskViewId
+ " taskId: " + getTaskIdsForTaskViewId(taskViewId)[0]
+ " for taskView: " + taskView + "\n");
}
Log.d(TASK_VIEW_ID_CRASH, "taskViewCount: " + getTaskViewCount()
+ " " + sb.toString());
mRunningTaskViewId = -1;
} else {
if (newRunningTaskView != null) {
mRunningTaskViewId = newRunningTaskView.getTaskViewId();
} else {
mRunningTaskViewId = -1;
}
}
@@ -1921,6 +1878,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
remoteTargetHandle.getTransformParams().setTargetSet(null);
remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true);
});
mSplitSelectStateController.resetState();
// These are relatively expensive and don't need to be done this frame (RecentsView isn't
// visible anyway), so defer by a frame to get off the critical path, e.g. app to home.
@@ -4380,6 +4338,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
public void setRecentsAnimationTargets(RecentsAnimationController recentsAnimationController,
RecentsAnimationTargets recentsAnimationTargets) {
mRecentsAnimationController = recentsAnimationController;
mSplitSelectStateController.setRecentsAnimationRunning(true);
if (recentsAnimationTargets == null || recentsAnimationTargets.apps.length == 0) {
return;
}
@@ -4479,6 +4438,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
// taps on QSB (3) user goes back to Overview and launch the most recent task.
setCurrentTask(-1);
mRecentsAnimationController = null;
mSplitSelectStateController.setRecentsAnimationRunning(false);
executeSideTaskLaunchCallback();
}
@@ -34,7 +34,6 @@ import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver.OnScrollChangedListener;
import android.widget.LinearLayout;
@@ -270,15 +269,9 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange
BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
int padding = getResources()
.getDimensionPixelSize(R.dimen.task_menu_vertical_padding);
if (deviceProfile.overviewShowAsGrid) {
// TODO(b/193432925) temporary so it doesn't look terrible on large screen
params.width =
getContext().getResources().getDimensionPixelSize(R.dimen.task_menu_width_grid);
} else {
params.width = orientationHandler
.getTaskMenuWidth(taskContainer.getThumbnailView(),
deviceProfile) - (2 * padding);
}
params.width = orientationHandler
.getTaskMenuWidth(taskContainer.getThumbnailView(),
deviceProfile) - (2 * padding);
// Gravity set to Left instead of Start as sTempRect.left measures Left distance not Start
params.gravity = Gravity.LEFT;
setLayoutParams(params);
@@ -349,13 +342,4 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange
return new RoundedRectRevealOutlineProvider(radius, radius, fromRect, toRect);
}
public View findMenuItemByText(String text) {
for (int i = mOptionLayout.getChildCount() - 1; i >= 0; --i) {
final ViewGroup menuOptionView = (ViewGroup) mOptionLayout.getChildAt(i);
if (text.equals(menuOptionView.<TextView>findViewById(R.id.text).getText())) {
return menuOptionView;
}
}
return null;
}
}
@@ -1,14 +1,167 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.views
import android.util.Log
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.Rect
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RectShape
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import com.android.launcher3.BaseDraggingActivity
import com.android.launcher3.DeviceProfile
import com.android.launcher3.R
import com.android.launcher3.popup.ArrowPopup
import com.android.launcher3.popup.SystemShortcut
import com.android.launcher3.util.Themes
import com.android.quickstep.KtR
import com.android.quickstep.TaskOverlayFactory
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
// TODO(http://b/193432925)
class TaskMenuViewWithArrow {
class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
companion object {
const val TAG = "TaskMenuViewWithArrow"
fun logSomething() {
Log.d(TAG, "It worked!")
fun showForTask(taskContainer: TaskIdAttributeContainer): Boolean {
val activity = BaseDraggingActivity
.fromContext<BaseDraggingActivity>(taskContainer.taskView.context)
val taskMenuViewWithArrow = activity.layoutInflater
.inflate(KtR.layout.task_menu_with_arrow, activity.dragLayer, false) as TaskMenuViewWithArrow<*>
return taskMenuViewWithArrow.populateAndShowForTask(taskContainer)
}
}
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
init {
clipToOutline = true
}
private val menuWidth = context.resources.getDimensionPixelSize(R.dimen.task_menu_width_grid)
private lateinit var taskView: TaskView
private lateinit var optionLayout: LinearLayout
private lateinit var taskContainer: TaskIdAttributeContainer
override fun isOfType(type: Int): Boolean = type and TYPE_TASK_MENU != 0
override fun getTargetObjectLocation(outPos: Rect?) {
popupContainer.getDescendantRectRelativeToSelf(taskView.iconView, outPos)
}
override fun onControllerInterceptTouchEvent(ev: MotionEvent?): Boolean {
if (ev?.action == MotionEvent.ACTION_DOWN) {
if (!popupContainer.isEventOverView(this, ev)) {
close(true)
return true
}
}
return false
}
override fun onFinishInflate() {
super.onFinishInflate()
optionLayout = findViewById(KtR.id.menu_option_layout)
}
private fun populateAndShowForTask(taskContainer: TaskIdAttributeContainer): Boolean {
if (isAttachedToWindow) {
return false
}
taskView = taskContainer.taskView
this.taskContainer = taskContainer
if (!populateMenu()) return false
show()
return true
}
/** @return true if successfully able to populate task view menu, false otherwise
*/
private fun populateMenu(): Boolean {
// Icon may not be loaded
if (taskContainer.task.icon == null) return false
addMenuOptions()
return true
}
private fun addMenuOptions() {
// Add the options
TaskOverlayFactory
.getEnabledShortcuts(taskView, mActivityContext.deviceProfile, taskContainer)
.forEach { this.addMenuOption(it) }
// Add the spaces between items
val divider = ShapeDrawable(RectShape())
divider.paint.color = resources.getColor(android.R.color.transparent)
val dividerSpacing = resources.getDimension(KtR.dimen.task_menu_spacing).toInt()
optionLayout.showDividers = SHOW_DIVIDER_MIDDLE
// Set the orientation, which makes the menu show
val recentsView: RecentsView<*, *> = mActivityContext.getOverviewPanel()
val orientationHandler = recentsView.pagedOrientationHandler
val deviceProfile: DeviceProfile = mActivityContext.deviceProfile
orientationHandler.setTaskOptionsMenuLayoutOrientation(
deviceProfile,
optionLayout,
dividerSpacing,
divider
)
}
private fun addMenuOption(menuOption: SystemShortcut<*>) {
val menuOptionView = mActivityContext.layoutInflater.inflate(
KtR.layout.task_view_menu_option, this, false
) as LinearLayout
menuOption.setIconAndLabelFor(
menuOptionView.findViewById(R.id.icon),
menuOptionView.findViewById(R.id.text)
)
val lp = menuOptionView.layoutParams as LayoutParams
lp.width = menuWidth
menuOptionView.setOnClickListener { view: View? -> menuOption.onClick(view) }
optionLayout.addView(menuOptionView)
}
override fun assignMarginsAndBackgrounds(viewGroup: ViewGroup) {
assignMarginsAndBackgrounds(this, Themes.getAttrColor(context, com.android.internal.R.attr.colorSurface))
}
override fun onCreateOpenAnimation(anim: AnimatorSet) {
anim.play(
ObjectAnimator.ofFloat(
taskContainer.thumbnailView, TaskThumbnailView.DIM_ALPHA,
TaskView.MAX_PAGE_SCRIM_ALPHA
)
)
}
override fun onCreateCloseAnimation(anim: AnimatorSet) {
anim.play(
ObjectAnimator.ofFloat(taskContainer.thumbnailView, TaskThumbnailView.DIM_ALPHA, 0f)
)
}
}
@@ -95,7 +95,6 @@ import com.android.quickstep.util.CancellableTask;
import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.TaskCornerRadius;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper;
import com.android.systemui.shared.recents.model.Task;
@@ -558,6 +557,10 @@ public class TaskView extends FrameLayout implements Reusable {
return mTaskIdContainer;
}
public boolean containsMultipleTasks() {
return mTaskIdContainer[1] != -1;
}
public TaskThumbnailView getThumbnail() {
return mSnapshotView;
}
@@ -690,13 +693,8 @@ public class TaskView extends FrameLayout implements Reusable {
TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
ActivityOptionsWrapper opts = mActivity.getActivityLaunchOptions(this, null);
opts.options.setLaunchDisplayId(getRootViewDisplayId());
boolean isOldTaskSplit = LauncherSplitScreenListener.INSTANCE.getNoCreate()
.getPersistentSplitIds().length > 0;
if (ActivityManagerWrapper.getInstance()
.startActivityFromRecents(mTask.key, opts.options)) {
if (isOldTaskSplit) {
SystemUiProxy.INSTANCE.getNoCreate().exitSplitScreen(mTask.key.id);
}
RecentsView recentsView = getRecentsView();
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && recentsView.getRunningTaskViewId() != -1) {
recentsView.onTaskLaunchedInLiveTileMode();
@@ -839,9 +837,11 @@ public class TaskView extends FrameLayout implements Reusable {
}
protected boolean showTaskMenuWithContainer(IconView iconView) {
// TODO(http://b/193432925)
if (DEBUG) TaskMenuViewWithArrow.Companion.logSomething();
return TaskMenuView.showForTask(mTaskIdAttributeContainer[0]);
if (mActivity.getDeviceProfile().overviewShowAsGrid) {
return TaskMenuViewWithArrow.Companion.showForTask(mTaskIdAttributeContainer[0]);
} else {
return TaskMenuView.showForTask(mTaskIdAttributeContainer[0]);
}
}
protected void setIcon(IconView iconView, Drawable icon) {
@@ -851,7 +851,15 @@ public class TaskView extends FrameLayout implements Reusable {
if (confirmSecondSplitSelectApp()) {
return;
}
showTaskMenu(iconView);
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask()) {
RecentsView recentsView = getRecentsView();
recentsView.switchToScreenshot(
() -> recentsView.finishRecentsAnimation(true /* toRecents */,
false /* shouldPip */,
() -> showTaskMenu(iconView)));
} else {
showTaskMenu(iconView);
}
});
iconView.setOnLongClickListener(v -> {
requestDisallowInterceptTouchEvent(true);
@@ -30,9 +30,7 @@ import android.app.ActivityManager;
import androidx.test.filters.SmallTest;
import com.android.launcher3.util.LooperExecutor;
import com.android.systemui.shared.recents.model.GroupTask;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.system.KeyguardManagerCompat;
import com.android.wm.shell.util.GroupedRecentTaskInfo;
@@ -73,7 +71,7 @@ public class RecentTasksListTest {
@Test
public void loadTasksInBackground_onlyKeys_noValidTaskDescription() {
GroupedRecentTaskInfo recentTaskInfos = new GroupedRecentTaskInfo(
new ActivityManager.RecentTaskInfo(), new ActivityManager.RecentTaskInfo());
new ActivityManager.RecentTaskInfo(), new ActivityManager.RecentTaskInfo(), null);
when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
.thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
@@ -93,7 +91,7 @@ public class RecentTasksListTest {
ActivityManager.RecentTaskInfo task2 = new ActivityManager.RecentTaskInfo();
task2.taskDescription = new ActivityManager.TaskDescription();
GroupedRecentTaskInfo recentTaskInfos = new GroupedRecentTaskInfo(
task1, task2);
task1, task2, null);
when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
.thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
+10
View File
@@ -154,6 +154,7 @@ import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.pm.PinRequestHelper;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.popup.ArrowPopup;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.popup.SystemShortcut;
@@ -3032,4 +3033,13 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
public StatsLogManager getStatsLogManager() {
return super.getStatsLogManager().withDefaultInstanceId(mAllAppsSessionLogId);
}
/**
* Returns the current popup for testing, if any.
*/
@VisibleForTesting
@Nullable
public ArrowPopup<?> getOptionsPopup() {
return findViewById(R.id.popup_container);
}
}
@@ -518,7 +518,10 @@ public class StatsLogManager implements ResourceBasedOverride {
LAUNCHER_TASKBAR_LONGPRESS_HIDE(896),
@UiEvent(doc = "User long pressed on the taskbar gesture handle to show the taskbar")
LAUNCHER_TASKBAR_LONGPRESS_SHOW(897);
LAUNCHER_TASKBAR_LONGPRESS_SHOW(897),
@UiEvent(doc = "User clicks on the search icon on header to launch search in app.")
LAUNCHER_ALLAPPS_SEARCHINAPP_LAUNCH(913);
// ADD MORE
@@ -46,6 +46,7 @@ public class SearchActionItemInfo extends ItemInfoWithIcon {
public static final int FLAG_PRIMARY_ICON_FROM_TITLE = 1 << 4;
public static final int FLAG_BADGE_WITH_COMPONENT_NAME = 1 << 5;
public static final int FLAG_ALLOW_PINNING = 1 << 6;
public static final int FLAG_SEARCH_IN_APP = 1 << 7;
private String mFallbackPackageName;
private int mFlags = 0;
@@ -234,7 +234,7 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
* @param backgroundColor When Color.TRANSPARENT, we get color from {@link #mColorIds}.
* Otherwise, we will use this color for all child views.
*/
private void assignMarginsAndBackgrounds(ViewGroup viewGroup, int backgroundColor) {
protected void assignMarginsAndBackgrounds(ViewGroup viewGroup, int backgroundColor) {
int[] colors = null;
if (backgroundColor == Color.TRANSPARENT) {
// Lazily get the colors so they match the current wallpaper colors.
@@ -445,7 +445,7 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
animateOpen();
}
private void setupForDisplay() {
protected void setupForDisplay() {
setVisibility(View.INVISIBLE);
mIsOpen = true;
getPopupContainer().addView(this);
@@ -482,7 +482,7 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
mArrow.setVisibility(show && shouldAddArrow() ? VISIBLE : INVISIBLE);
}
private void addArrow() {
protected void addArrow() {
getPopupContainer().addView(mArrow);
mArrow.setX(getX() + getArrowLeft());
@@ -686,12 +686,13 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
return getChildCount() > 0 ? getChildAt(0) : this;
}
private void animateOpen() {
protected void animateOpen() {
setVisibility(View.VISIBLE);
mOpenCloseAnimator = getOpenCloseAnimator(true, OPEN_DURATION, OPEN_FADE_START_DELAY,
OPEN_FADE_DURATION, OPEN_CHILD_FADE_START_DELAY, OPEN_CHILD_FADE_DURATION,
DECELERATED_EASE);
onCreateOpenAnimation(mOpenCloseAnimator);
mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -784,6 +785,11 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
mOpenCloseAnimator.start();
}
/**
* Called when creating the open transition allowing subclass can add additional animations.
*/
protected void onCreateOpenAnimation(AnimatorSet anim) { }
/**
* Called when creating the close transition allowing subclass can add additional animations.
*/
@@ -17,6 +17,7 @@ package com.android.launcher3.touch;
import static com.android.launcher3.Launcher.REQUEST_BIND_PENDING_APPWIDGET;
import static com.android.launcher3.Launcher.REQUEST_RECONFIGURE_APPWIDGET;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SEARCHINAPP_LAUNCH;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER;
@@ -286,7 +287,13 @@ public class ItemClickHandler {
Toast.LENGTH_SHORT).show();
}
}
launcher.getStatsLogManager().logger().withItemInfo(itemInfo).log(LAUNCHER_APP_LAUNCH_TAP);
if (itemInfo.hasFlags(SearchActionItemInfo.FLAG_SEARCH_IN_APP)) {
launcher.getStatsLogManager().logger().withItemInfo(itemInfo).log(
LAUNCHER_ALLAPPS_SEARCHINAPP_LAUNCH);
} else {
launcher.getStatsLogManager().logger().withItemInfo(itemInfo).log(
LAUNCHER_APP_LAUNCH_TAP);
}
}
private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
@@ -390,7 +390,7 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
@Override
public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
int parentWidth, int parentHeight,
SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig, DeviceProfile dp) {
StagedSplitBounds splitBoundsConfig, DeviceProfile dp) {
int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
int dividerBar = splitBoundsConfig.visualDividerBounds.width();
@@ -435,15 +435,18 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
FrameLayout.LayoutParams secondaryIconParams =
new FrameLayout.LayoutParams(primaryIconParams);
int dividerBar = (splitConfig.appsStackedVertically ?
splitConfig.visualDividerBounds.height() :
splitConfig.visualDividerBounds.width());
int primaryHeight = primarySnapshotBounds.height();
int secondaryHeight = secondarySnapshotBounds.height();
primaryIconParams.gravity = (isRtl ? START : END) | TOP;
primaryIconView.setTranslationY((primaryHeight + taskIconHeight) / 2f );
primaryIconView.setTranslationY(primaryHeight - primaryIconView.getHeight() / 2f);
primaryIconView.setTranslationX(0);
secondaryIconParams.gravity = (isRtl ? START : END) | TOP;
secondaryIconView.setTranslationY(primaryHeight
+ ((secondaryHeight + taskIconHeight) / 2f));
secondaryIconView.setTranslationY(primaryHeight + taskIconHeight + dividerBar);
secondaryIconView.setTranslationX(0);
primaryIconView.setLayoutParams(primaryIconParams);
secondaryIconView.setLayoutParams(secondaryIconParams);
}
@@ -141,13 +141,12 @@ public interface PagedOrientationHandler {
* @param desiredStagePosition Which stage position (topLeft/rightBottom) we want to resize
* outRect for
*/
void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect,
StagedSplitBounds splitInfo,
void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect, StagedSplitBounds splitInfo,
@SplitConfigurationOptions.StagePosition int desiredStagePosition);
void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
int parentWidth, int parentHeight,
SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig, DeviceProfile dp);
StagedSplitBounds splitBoundsConfig, DeviceProfile dp);
// Overview TaskMenuView methods
void setIconAndSnapshotParams(View iconView, int taskIconMargin, int taskIconHeight,
@@ -16,7 +16,6 @@
package com.android.launcher3.touch;
import static android.view.Gravity.BOTTOM;
import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.view.Gravity.START;
import static android.view.Gravity.TOP;
@@ -477,7 +476,7 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
@Override
public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
int parentWidth, int parentHeight,
SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig, DeviceProfile dp) {
StagedSplitBounds splitBoundsConfig, DeviceProfile dp) {
int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
int dividerBar = (splitBoundsConfig.appsStackedVertically ?
@@ -535,23 +534,27 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
FrameLayout.LayoutParams secondaryIconParams =
new FrameLayout.LayoutParams(primaryIconParams);
int dividerBar = (splitConfig.appsStackedVertically ?
splitConfig.visualDividerBounds.height() :
splitConfig.visualDividerBounds.width());
int primaryWidth = primarySnapshotBounds.width();
if (deviceProfile.isLandscape) {
int primaryWidth = primarySnapshotBounds.width();
int secondaryWidth = secondarySnapshotBounds.width();
primaryIconParams.gravity = TOP | START;
primaryIconView.setTranslationX((primaryWidth - taskIconHeight) / 2f );
primaryIconView.setTranslationX(primaryWidth - primaryIconView.getWidth());
primaryIconView.setTranslationY(0);
secondaryIconParams.gravity = TOP | START;
secondaryIconView.setTranslationX(primaryWidth
+ ((secondaryWidth - taskIconHeight) / 2f));
} else {
primaryIconView.setTranslationX(0);
secondaryIconView.setTranslationX(0);
primaryIconView.setTranslationY(0);
secondaryIconView.setTranslationX(primaryWidth + dividerBar);
secondaryIconView.setTranslationY(0);
} else {
primaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
primaryIconView.setTranslationX(-(primaryIconView.getWidth()) / 2f);
primaryIconView.setTranslationY(0);
secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
secondaryIconView.setTranslationX(secondaryIconView.getWidth() / 2f);
secondaryIconView.setTranslationY(0);
secondaryIconParams.gravity = BOTTOM | CENTER_HORIZONTAL;
secondaryIconParams.bottomMargin = -(secondaryIconParams.topMargin + taskIconHeight);
}
primaryIconView.setLayoutParams(primaryIconParams);
secondaryIconView.setLayoutParams(secondaryIconParams);
@@ -19,6 +19,7 @@ package com.android.launcher3.touch;
import static android.view.Gravity.CENTER_VERTICAL;
import static android.view.Gravity.END;
import static android.view.Gravity.START;
import static android.view.Gravity.TOP;
import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -36,7 +37,9 @@ import android.widget.LinearLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import com.android.launcher3.views.BaseDragLayer;
import java.util.Collections;
@@ -127,6 +130,23 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
iconParams.topMargin = snapshotParams.topMargin / 2;
}
@Override
public void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, Rect primarySnapshotBounds, Rect secondarySnapshotBounds,
boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig) {
super.setSplitIconParams(primaryIconView, secondaryIconView, taskIconHeight,
primarySnapshotBounds, secondarySnapshotBounds, isRtl, deviceProfile, splitConfig);
FrameLayout.LayoutParams primaryIconParams =
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
FrameLayout.LayoutParams secondaryIconParams =
(FrameLayout.LayoutParams) secondaryIconView.getLayoutParams();
primaryIconParams.gravity = (isRtl ? END : START) | TOP;
secondaryIconParams.gravity = (isRtl ? END : START) | TOP;
primaryIconView.setLayoutParams(primaryIconParams);
secondaryIconView.setLayoutParams(secondaryIconParams);
}
/* ---------- The following are only used by TaskViewTouchHandler. ---------- */
@Override
@@ -85,6 +85,12 @@ public final class SplitConfigurationOptions {
}
}
/**
* NOTE: Engineers complained about too little ambiguity in the last survey, so there is a class
* with the same name/functionality in wm.shell.util (which launcher3 cannot be built against)
*
* If you make changes here, consider making the same changes there
*/
public static class StagedSplitBounds {
public final Rect leftTopBounds;
public final Rect rightBottomBounds;
@@ -100,10 +106,15 @@ public final class SplitConfigurationOptions {
* the bounds were originally in
*/
public final boolean appsStackedVertically;
public final int leftTopTaskId;
public final int rightBottomTaskId;
public StagedSplitBounds(Rect leftTopBounds, Rect rightBottomBounds) {
public StagedSplitBounds(Rect leftTopBounds, Rect rightBottomBounds, int leftTopTaskId,
int rightBottomTaskId) {
this.leftTopBounds = leftTopBounds;
this.rightBottomBounds = rightBottomBounds;
this.leftTopTaskId = leftTopTaskId;
this.rightBottomTaskId = rightBottomTaskId;
if (rightBottomBounds.top > leftTopBounds.top) {
// vertical apps, horizontal divider
@@ -37,7 +37,6 @@ import android.view.View.OnLongClickListener;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.content.ContextCompat;
import com.android.launcher3.AbstractFloatingView;
@@ -176,11 +175,6 @@ public class OptionsPopupView extends ArrowPopup<Launcher>
return children;
}
@VisibleForTesting
public static ArrowPopup getOptionsPopup(Launcher launcher) {
return launcher.findViewById(R.id.popup_container);
}
/**
* Returns the list of supported actions
*/
@@ -38,7 +38,6 @@ import com.android.launcher3.tapl.Folder;
import com.android.launcher3.tapl.FolderIcon;
import com.android.launcher3.tapl.Widgets;
import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.views.OptionsPopupView;
import com.android.launcher3.widget.picker.WidgetsFullSheet;
import com.android.launcher3.widget.picker.WidgetsRecyclerView;
@@ -102,8 +101,8 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
mDevice.pressMenu();
mDevice.waitForIdle();
executeOnLauncher(
launcher -> assertTrue("Launcher internal state didn't switch to Showing Menu",
OptionsPopupView.getOptionsPopup(launcher) != null));
launcher -> assertNotNull("Launcher internal state didn't switch to Showing Menu",
launcher.getOptionsPopup()));
// Check that pressHome works when the menu is shown.
mLauncher.pressHome();
}
@@ -286,7 +285,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
}
private boolean isOptionsPopupVisible(Launcher launcher) {
final ArrowPopup popup = OptionsPopupView.getOptionsPopup(launcher);
final ArrowPopup<?> popup = launcher.getOptionsPopup();
return popup != null && popup.isShown();
}