Merge "Expose action that allows landing on the work tab"
diff --git a/quickstep/protos_overrides/launcher_atom_extension.proto b/quickstep/protos_overrides/launcher_atom_extension.proto
index d2dc0cb..ff050ea 100644
--- a/quickstep/protos_overrides/launcher_atom_extension.proto
+++ b/quickstep/protos_overrides/launcher_atom_extension.proto
@@ -23,20 +23,24 @@
// Message name should match with launcher_atom_extension.proto message at
// the AOSP level.
message ExtendedContainers {
+ reserved 2; // Deleted fields
oneof Container{
DeviceSearchResultContainer device_search_result_container = 1;
- CorrectedDeviceSearchResultContainer corrected_device_search_result_container = 2;
}
}
// Represents on-device search result container.
message DeviceSearchResultContainer{
optional int32 query_length = 1;
-}
+ optional SearchAttributes search_attributes = 2;
-// Represents on-device search result container with results from spell-corrected query.
-message CorrectedDeviceSearchResultContainer{
- optional int32 query_length = 1;
-}
+ message SearchAttributes{
+ // True if results are based on spell corrected query
+ optional bool corrected_query = 1;
+
+ // True if the item's title/content is a direct match to the search query, false otherwise.
+ optional bool direct_match = 2;
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 51c2294..af4f49d 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -21,7 +21,9 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.NO_OFFSET;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
+import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
@@ -63,6 +65,7 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ObjectWrapper;
+import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.util.UiThreadHelper;
import com.android.quickstep.OverviewCommandHelper;
import com.android.quickstep.RecentsModel;
@@ -89,6 +92,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
@@ -494,8 +498,20 @@
@Override
public Stream<SystemShortcut.Factory> getSupportedShortcuts() {
- return Stream.concat(Stream.of(WellbeingModel.SHORTCUT_FACTORY),
- super.getSupportedShortcuts());
+ Stream<SystemShortcut.Factory> base = Stream.of(WellbeingModel.SHORTCUT_FACTORY);
+ if (ENABLE_SPLIT_FROM_WORKSPACE.get() && mDeviceProfile.isTablet) {
+ RecentsView recentsView = getOverviewPanel();
+ // TODO: Pull it out of PagedOrentationHandler for split from workspace.
+ List<SplitPositionOption> positions =
+ recentsView.getPagedOrientationHandler().getSplitPositionOptions(
+ mDeviceProfile);
+ List<SystemShortcut.Factory<BaseQuickstepLauncher>> splitShortcuts = new ArrayList<>();
+ for (SplitPositionOption position : positions) {
+ splitShortcuts.add(getSplitSelectShortcutByPosition(position));
+ }
+ base = Stream.concat(base, splitShortcuts.stream());
+ }
+ return Stream.concat(base, super.getSupportedShortcuts());
}
@Override
diff --git a/quickstep/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
index 7c29c5b..d4bbfa2 100644
--- a/quickstep/src/com/android/launcher3/model/AppEventProducer.java
+++ b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
+import static com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers.ContainerCase.DEVICE_SEARCH_RESULT_CONTAINER;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_PREDICTION_PINNED;
@@ -293,10 +294,9 @@
case SEARCH_RESULT_CONTAINER:
return "search-results";
case EXTENDED_CONTAINERS: {
- switch(ci.getExtendedContainers().getContainerCase()) {
- case DEVICE_SEARCH_RESULT_CONTAINER:
- case CORRECTED_DEVICE_SEARCH_RESULT_CONTAINER:
- return "search-results";
+ if (ci.getExtendedContainers().getContainerCase()
+ == DEVICE_SEARCH_RESULT_CONTAINER) {
+ return "search-results";
}
}
default: // fall out
diff --git a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
new file mode 100644
index 0000000..3bc6576
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.popup;
+
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+import android.view.View;
+
+import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
+import com.android.quickstep.views.RecentsView;
+
+public interface QuickstepSystemShortcut {
+
+ String TAG = QuickstepSystemShortcut.class.getSimpleName();
+
+ static SystemShortcut.Factory<BaseQuickstepLauncher> getSplitSelectShortcutByPosition(
+ SplitPositionOption position) {
+ return (activity, itemInfo) -> new QuickstepSystemShortcut.SplitSelectSystemShortcut(
+ activity, itemInfo, position);
+ }
+
+ class SplitSelectSystemShortcut extends SystemShortcut<BaseQuickstepLauncher> {
+
+ private final BaseQuickstepLauncher mLauncher;
+ private final ItemInfo mItemInfo;
+ private final SplitPositionOption mPosition;
+
+ public SplitSelectSystemShortcut(BaseQuickstepLauncher launcher, ItemInfo itemInfo,
+ SplitPositionOption position) {
+ super(position.iconResId, position.textResId, launcher, itemInfo);
+
+ mLauncher = launcher;
+ mItemInfo = itemInfo;
+ mPosition = position;
+ }
+
+ @Override
+ public void onClick(View view) {
+ Bitmap bitmap;
+ Intent intent;
+ if (mItemInfo instanceof WorkspaceItemInfo) {
+ final WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) mItemInfo;
+ bitmap = workspaceItemInfo.bitmap.icon;
+ intent = workspaceItemInfo.intent;
+ } else if (mItemInfo instanceof com.android.launcher3.model.data.AppInfo) {
+ final com.android.launcher3.model.data.AppInfo appInfo =
+ (com.android.launcher3.model.data.AppInfo) mItemInfo;
+ bitmap = appInfo.bitmap.icon;
+ intent = appInfo.intent;
+ } else {
+ Log.e(TAG, "unknown item type");
+ return;
+ }
+
+ RecentsView recentsView = mLauncher.getOverviewPanel();
+ recentsView.initiateSplitSelect(
+ new SplitSelectSource(view, new BitmapDrawable(bitmap), intent, mPosition));
+ }
+ }
+
+ class SplitSelectSource {
+
+ public final View view;
+ public final Drawable drawable;
+ public final Intent intent;
+ public final SplitPositionOption position;
+
+ public SplitSelectSource(View view, Drawable drawable, Intent intent,
+ SplitPositionOption position) {
+ this.view = view;
+ this.drawable = drawable;
+ this.intent = intent;
+ this.position = position;
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 3242d42..d54b9e7 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -294,6 +294,11 @@
}
public void onOverlayScrollChanged(float progress) {
+ // Add some padding to the progress, such we don't change the depth on the last frames of
+ // the animation. It's possible that a user flinging the feed quickly would scroll
+ // horizontally by accident, causing the device to enter client composition unnecessarily.
+ progress = Math.min(progress * 1.1f, 1f);
+
// Round out the progress to dedupe frequent, non-perceptable updates
int progressI = (int) (progress * 256);
float progressF = Utilities.boundToRange(progressI / 256f, 0f, 1f);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 1761096..20762b9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -27,10 +27,8 @@
import android.animation.AnimatorSet;
import android.annotation.Nullable;
import android.content.SharedPreferences;
-import android.content.res.Resources;
import android.view.ViewConfiguration;
-import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.quickstep.AnimatedFloat;
@@ -146,10 +144,9 @@
public TaskbarStashController(TaskbarActivityContext activity) {
mActivity = activity;
mPrefs = Utilities.getPrefs(mActivity);
- final Resources resources = mActivity.getResources();
- mStashedHeight = resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity);
mUnstashedHeight = mActivity.getDeviceProfile().taskbarSize;
+ mStashedHeight = mActivity.getDeviceProfile().stashedTaskbarSize;
}
public void init(TaskbarControllers controllers, TaskbarSharedState sharedState) {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index bc06944..e218db1 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -249,6 +249,8 @@
private RunningWindowAnim[] mRunningWindowAnim;
// Possible second animation running at the same time as mRunningWindowAnim
private Animator mParallelRunningAnim;
+ // Current running divider animation
+ private ValueAnimator mDividerAnimator;
private boolean mIsMotionPaused;
private boolean mHasMotionEverBeenPaused;
@@ -831,8 +833,8 @@
// Notify when the animation starts
flushOnRecentsAnimationAndLauncherBound();
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
- false /*shown*/, true /*animate*/);
+ // Start hiding the divider
+ setDividerShown(false /* shown */, false /* immediate */);
// Only add the callback to enable the input consumer after we actually have the controller
mStateCallback.runOnceAtState(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED,
@@ -849,8 +851,7 @@
mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
if (mRecentsAnimationTargets != null) {
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
- true /*shown*/, true /*animate*/);
+ setDividerShown(true /* shown */, false /* immediate */);
}
// Defer clearing the controller and the targets until after we've updated the state
@@ -1000,8 +1001,7 @@
mStateCallback.setState(STATE_RESUME_LAST_TASK);
}
if (mRecentsAnimationTargets != null) {
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
- true /*shown*/, false /*animate*/);
+ setDividerShown(true /* shown */, true /* immediate */);
}
break;
}
@@ -1653,8 +1653,7 @@
mActivityInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget());
if (mRecentsAnimationTargets != null) {
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
- true /*shown*/, false /*animate*/);
+ setDividerShown(true /* shown */, true /* immediate */);
}
// Leave the pending invisible flag, as it may be used by wallpaper open animation.
@@ -1920,8 +1919,7 @@
@Override
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
if (!controller.getFinishTargetIsLauncher()) {
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
- true /*shown*/, true /*animate*/);
+ setDividerShown(true /* shown */, false /* immediate */);
}
mRecentsAnimationController = null;
mRecentsAnimationTargets = null;
@@ -2026,6 +2024,19 @@
return scaleProgress;
}
+ private void setDividerShown(boolean shown, boolean immediate) {
+ if (mDividerAnimator != null) {
+ mDividerAnimator.cancel();
+ }
+ mDividerAnimator = TaskViewUtils.createSplitAuxiliarySurfacesAnimator(
+ mRecentsAnimationTargets.nonApps, shown, (dividerAnimator) -> {
+ dividerAnimator.start();
+ if (immediate) {
+ dividerAnimator.end();
+ }
+ });
+ }
+
/**
* Used for winscope tracing, see launcher_trace.proto
* @see com.android.systemui.shared.tracing.ProtoTraceable#writeToProto
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 22a30e9..4aa69d1 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -608,6 +608,21 @@
}
}
+ public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent,
+ Intent fillInIntent, int taskId, boolean intentFirst, Bundle mainOptions,
+ Bundle sideOptions, @SplitConfigurationOptions.StagePosition int sidePosition,
+ float splitRatio, RemoteAnimationAdapter adapter) {
+ if (mSystemUiProxy != null) {
+ try {
+ mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, fillInIntent,
+ taskId, intentFirst, mainOptions, sideOptions, sidePosition, splitRatio,
+ adapter);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call startTasksWithLegacyTransition");
+ }
+ }
+ }
+
public void startShortcut(String packageName, String shortcutId, int position,
Bundle options, UserHandle user) {
if (mSplitScreen != null) {
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 5afcdcb..e67b0a5 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -15,6 +15,7 @@
*/
package com.android.quickstep;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -46,6 +47,7 @@
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
+import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Matrix;
@@ -86,6 +88,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
/**
* Utility class for helpful methods related to {@link TaskView} objects and their tasks.
@@ -389,18 +392,20 @@
* device is considered in multiWindowMode and things like insets and stuff change
* and calculations have to be adjusted in the animations for that
*/
- public static void composeRecentsSplitLaunchAnimator(@NonNull Task initalTask,
- @NonNull Task secondTask, @NonNull TransitionInfo transitionInfo,
- SurfaceControl.Transaction t, @NonNull Runnable finishCallback) {
-
- final TransitionInfo.Change[] splitRoots = new TransitionInfo.Change[2];
+ public static void composeRecentsSplitLaunchAnimator(int initialTaskId,
+ @Nullable PendingIntent initialTaskPendingIntent, int secondTaskId,
+ @NonNull TransitionInfo transitionInfo, SurfaceControl.Transaction t,
+ @NonNull Runnable finishCallback) {
+ // TODO: consider initialTaskPendingIntent
+ TransitionInfo.Change splitRoot1 = null;
+ TransitionInfo.Change splitRoot2 = null;
for (int i = 0; i < transitionInfo.getChanges().size(); ++i) {
final TransitionInfo.Change change = transitionInfo.getChanges().get(i);
final int taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1;
final int mode = change.getMode();
// Find the target tasks' root tasks since those are the split stages that need to
// be animated (the tasks themselves are children and thus inherit animation).
- if (taskId == initalTask.key.id || taskId == secondTask.key.id) {
+ if (taskId == initialTaskId || taskId == secondTaskId) {
if (!(mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
throw new IllegalStateException(
"Expected task to be showing, but it is " + mode);
@@ -409,16 +414,18 @@
throw new IllegalStateException("Initiating multi-split launch but the split"
+ "root of " + taskId + " is already visible or has broken hierarchy.");
}
- splitRoots[taskId == initalTask.key.id ? 0 : 1] =
- transitionInfo.getChange(change.getParent());
+ }
+ if (taskId == initialTaskId && initialTaskId != INVALID_TASK_ID) {
+ splitRoot1 = transitionInfo.getChange(change.getParent());
+ }
+ if (taskId == secondTaskId) {
+ splitRoot2 = transitionInfo.getChange(change.getParent());
}
}
// This is where we should animate the split roots. For now, though, just make them visible.
- for (int i = 0; i < 2; ++i) {
- t.show(splitRoots[i].getLeash());
- t.setAlpha(splitRoots[i].getLeash(), 1.f);
- }
+ animateSplitRoot(t, splitRoot1);
+ animateSplitRoot(t, splitRoot2);
// This contains the initial state (before animation), so apply this at the beginning of
// the animation.
@@ -428,6 +435,14 @@
finishCallback.run();
}
+ private static void animateSplitRoot(SurfaceControl.Transaction t,
+ TransitionInfo.Change splitRoot) {
+ if (splitRoot != null) {
+ t.show(splitRoot.getLeash());
+ t.setAlpha(splitRoot.getLeash(), 1.f);
+ }
+ }
+
/**
* Legacy version (until shell transitions are enabled)
*
@@ -440,9 +455,9 @@
* If it is null, then it will simply fade in the starting apps and fade out launcher (for the
* case where launcher handles animating starting split tasks from app icon) */
public static void composeRecentsSplitLaunchAnimatorLegacy(
- @Nullable GroupedTaskView launchingTaskView,
- @NonNull Task initialTask,
- @NonNull Task secondTask, @NonNull RemoteAnimationTargetCompat[] appTargets,
+ @Nullable GroupedTaskView launchingTaskView, int initialTaskId,
+ @Nullable PendingIntent initialTaskPendingIntent, int secondTaskId,
+ @NonNull RemoteAnimationTargetCompat[] appTargets,
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
@NonNull RemoteAnimationTargetCompat[] nonAppTargets,
@NonNull StateManager stateManager,
@@ -478,7 +493,7 @@
if (mode == MODE_OPENING) {
openingTargets.add(leash);
- } else if (taskId == initialTask.key.id || taskId == secondTask.key.id) {
+ } else if (taskId == initialTaskId || taskId == secondTaskId) {
throw new IllegalStateException("Expected task to be opening, but it is " + mode);
} else if (mode == MODE_CLOSING) {
closingTargets.add(leash);
@@ -540,8 +555,16 @@
nonAppTargets, depthController, pa);
if (launcherClosing) {
// TODO(b/182592057): differentiate between "restore split" vs "launch fullscreen app"
- TaskViewUtils.setSplitAuxiliarySurfacesShown(nonAppTargets,
- true /*shown*/, true /*animate*/, pa);
+ TaskViewUtils.createSplitAuxiliarySurfacesAnimator(nonAppTargets, true /*shown*/,
+ (dividerAnimator) -> {
+ // If split apps are launching, we want to delay showing the divider bar
+ // until the very end once the apps are mostly in place. This is because we
+ // aren't moving the divider leash in the relative position with the
+ // launching apps.
+ dividerAnimator.setStartDelay(pa.getDuration()
+ - SPLIT_DIVIDER_ANIM_DURATION);
+ pa.add(dividerAnimator);
+ });
}
Animator childStateAnimation = null;
@@ -596,16 +619,17 @@
anim.addListener(windowAnimEndListener);
}
- public static void setSplitAuxiliarySurfacesShown(RemoteAnimationTargetCompat[] nonApps,
- boolean shown, boolean animate) {
- setSplitAuxiliarySurfacesShown(nonApps, shown, animate,null);
- }
-
- private static void setSplitAuxiliarySurfacesShown(
- @NonNull RemoteAnimationTargetCompat[] nonApps, boolean shown, boolean animate,
- @Nullable PendingAnimation splitLaunchAnimation) {
+ /**
+ * Creates an animation to show/hide the auxiliary surfaces (aka. divider bar), only calling
+ * {@param animatorHandler} if there are valid surfaces to animate.
+ *
+ * @return the animator animating the surfaces
+ */
+ public static ValueAnimator createSplitAuxiliarySurfacesAnimator(
+ RemoteAnimationTargetCompat[] nonApps, boolean shown,
+ Consumer<ValueAnimator> animatorHandler) {
if (nonApps == null || nonApps.length == 0) {
- return;
+ return null;
}
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
@@ -620,20 +644,7 @@
}
}
if (!hasSurfaceToAnimate) {
- return;
- }
-
- if (!animate) {
- for (SurfaceControl leash : auxiliarySurfaces) {
- t.setAlpha(leash, shown ? 1 : 0);
- if (shown) {
- t.show(leash);
- } else {
- t.hide(leash);
- }
- }
- t.apply();
- return;
+ return null;
}
ValueAnimator dockFadeAnimator = ValueAnimator.ofFloat(0f, 1f);
@@ -670,15 +681,7 @@
}
});
dockFadeAnimator.setDuration(SPLIT_DIVIDER_ANIM_DURATION);
- if (splitLaunchAnimation != null) {
- // If split apps are launching, we want to delay showing the divider bar until the very
- // end once the apps are mostly in place. This is because we aren't moving the divider
- // leash in the relative position with the launching apps.
- dockFadeAnimator.setStartDelay(
- splitLaunchAnimation.getDuration() - SPLIT_DIVIDER_ANIM_DURATION);
- splitLaunchAnimation.add(dockFadeAnimator);
- } else {
- dockFadeAnimator.start();
- }
+ animatorHandler.accept(dockFadeAnimator);
+ return dockFadeAnimator;
}
}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 69da977..c7a8382 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -34,6 +34,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.popup.QuickstepSystemShortcut;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.quickstep.FallbackActivityInterface;
@@ -254,4 +255,10 @@
// Do not let touch escape to siblings below this view.
return result || mActivity.getStateManager().getState().overviewUi();
}
+
+ @Override
+ public void initiateSplitSelect(QuickstepSystemShortcut.SplitSelectSource splitSelectSource) {
+ super.initiateSplitSelect(splitSelectSource);
+ mActivity.getStateManager().goToState(OVERVIEW_SPLIT_SELECT);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 676161e..ad52a66 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -48,6 +48,7 @@
import com.android.launcher3.logger.LauncherAtom.FromState;
import com.android.launcher3.logger.LauncherAtom.ToState;
import com.android.launcher3.logger.LauncherAtomExtensions.DeviceSearchResultContainer;
+import com.android.launcher3.logger.LauncherAtomExtensions.DeviceSearchResultContainer.SearchAttributes;
import com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager;
@@ -89,6 +90,12 @@
private static final int EXTENDED_CONTAINERS_HIERARCHY_OFFSET = 300;
private static final int ATTRIBUTE_MULTIPLIER = 100;
+ /**
+ * Flags for converting SearchAttribute to integer value.
+ */
+ private static final int SEARCH_ATTRIBUTES_CORRECTED_QUERY = 1;
+ private static final int SEARCH_ATTRIBUTES_DIRECT_MATCH = 1 << 1;
+
public static final CopyOnWriteArrayList<StatsLogConsumer> LOGS_CONSUMER =
new CopyOnWriteArrayList<>();
@@ -405,7 +412,10 @@
atomInfo.getFolderIcon().getToLabelState().getNumber() /* toState */,
atomInfo.getFolderIcon().getLabelInfo() /* edittext */,
getCardinality(atomInfo) /* cardinality */,
- getFeatures(atomInfo) /* features */);
+ getFeatures(atomInfo) /* features */
+ // TODO(b/217753033) : Add SearchAttributes field after necessary approval
+ // getSearchAttributes(atomInfo) /* searchAttributes */
+ );
}
}
@@ -561,6 +571,25 @@
return 0;
}
+ private static int getSearchAttributes(LauncherAtom.ItemInfo info) {
+ if (info.getContainerInfo().getExtendedContainers().getDeviceSearchResultContainer()
+ .hasSearchAttributes()) {
+ return searchAttributesToInt(info.getContainerInfo().getExtendedContainers()
+ .getDeviceSearchResultContainer().getSearchAttributes());
+ }
+ return 0;
+ }
+
+ private static int searchAttributesToInt(SearchAttributes searchAttributes) {
+ int response = 0;
+ if (searchAttributes.getCorrectedQuery()) {
+ response = response | SEARCH_ATTRIBUTES_CORRECTED_QUERY;
+ }
+ if (searchAttributes.getDirectMatch()) {
+ response = response | SEARCH_ATTRIBUTES_DIRECT_MATCH;
+ }
+ return response;
+ }
/**
* Interface to get stats log while it is dispatched to the system
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 5253e8c..e856d8a 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -16,6 +16,8 @@
package com.android.quickstep.util;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
@@ -24,7 +26,8 @@
import android.app.ActivityOptions;
import android.app.ActivityThread;
-import android.graphics.Rect;
+import android.app.PendingIntent;
+import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.view.RemoteAnimationAdapter;
@@ -42,7 +45,6 @@
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.TaskView;
-import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -62,16 +64,16 @@
private final StateManager mStateManager;
private final DepthController mDepthController;
private @StagePosition int mStagePosition;
- private Task mInitialTask;
- private Task mSecondTask;
+ private PendingIntent mInitialTaskPendingIntent;
+ private int mInitialTaskId = INVALID_TASK_ID;
+ private int mSecondTaskId = INVALID_TASK_ID;
private boolean mRecentsAnimationRunning;
/** If not null, this is the TaskView we want to launch from */
@Nullable
private GroupedTaskView mLaunchingTaskView;
public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy,
- StateManager stateManager,
- DepthController depthController) {
+ StateManager stateManager, DepthController depthController) {
mHandler = handler;
mSystemUiProxy = systemUiProxy;
mStateManager = stateManager;
@@ -81,19 +83,26 @@
/**
* To be called after first task selected
*/
- public void setInitialTaskSelect(Task task, @StagePosition int stagePosition,
- Rect initialBounds) {
- mInitialTask = task;
+ public void setInitialTaskSelect(int taskId, @StagePosition int stagePosition) {
+ mInitialTaskId = taskId;
mStagePosition = stagePosition;
+ mInitialTaskPendingIntent = null;
+ }
+
+ public void setInitialTaskSelect(PendingIntent pendingIntent,
+ @StagePosition int stagePosition) {
+ mInitialTaskPendingIntent = pendingIntent;
+ mStagePosition = stagePosition;
+ mInitialTaskId = INVALID_TASK_ID;
}
/**
* To be called after second task selected
*/
- public void setSecondTaskId(Task task, Consumer<Boolean> callback) {
- mSecondTask = task;
- launchTasks(mInitialTask, mSecondTask, mStagePosition, callback,
- false /* freezeTaskList */, DEFAULT_SPLIT_RATIO);
+ public void setSecondTaskId(int taskId, Consumer<Boolean> callback) {
+ mSecondTaskId = taskId;
+ launchTasks(mInitialTaskId, mInitialTaskPendingIntent, mSecondTaskId, mStagePosition,
+ callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO);
}
/**
@@ -104,7 +113,8 @@
mLaunchingTaskView = groupedTaskView;
TaskView.TaskIdAttributeContainer[] taskIdAttributeContainers =
groupedTaskView.getTaskIdAttributeContainers();
- launchTasks(taskIdAttributeContainers[0].getTask(), taskIdAttributeContainers[1].getTask(),
+ launchTasks(taskIdAttributeContainers[0].getTask().key.id, null,
+ taskIdAttributeContainers[1].getTask().key.id,
taskIdAttributeContainers[0].getStagePosition(), callback, freezeTaskList,
groupedTaskView.getSplitRatio());
}
@@ -112,22 +122,25 @@
/**
* @param stagePosition representing location of task1
*/
- public void launchTasks(Task task1, Task task2, @StagePosition int stagePosition,
- Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) {
+ public void launchTasks(int taskId1, @Nullable PendingIntent taskPendingIntent,
+ int taskId2, @StagePosition int stagePosition, Consumer<Boolean> callback,
+ boolean freezeTaskList, float splitRatio) {
// Assume initial task is for top/left part of screen
final int[] taskIds = stagePosition == STAGE_POSITION_TOP_OR_LEFT
- ? new int[]{task1.key.id, task2.key.id}
- : new int[]{task2.key.id, task1.key.id};
+ ? new int[]{taskId1, taskId2}
+ : new int[]{taskId2, taskId1};
if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
RemoteSplitLaunchTransitionRunner animationRunner =
- new RemoteSplitLaunchTransitionRunner(task1, task2);
+ new RemoteSplitLaunchTransitionRunner(taskId1, taskPendingIntent, taskId2);
mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, splitRatio,
new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR,
ActivityThread.currentActivityThread().getApplicationThread()));
+ // TODO: handle intent + task with shell transition
} else {
RemoteSplitLaunchAnimationRunner animationRunner =
- new RemoteSplitLaunchAnimationRunner(task1, task2, callback);
+ new RemoteSplitLaunchAnimationRunner(taskId1, taskPendingIntent, taskId2,
+ callback);
final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
RemoteAnimationAdapterCompat.wrapRemoteAnimationRunner(animationRunner),
300, 150,
@@ -137,9 +150,16 @@
if (freezeTaskList) {
mainOpts.setFreezeRecentTasksReordering();
}
- mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], mainOpts.toBundle(),
- taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
- splitRatio, adapter);
+ if (taskPendingIntent == null) {
+ mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], mainOpts.toBundle(),
+ taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
+ splitRatio, adapter);
+ } else {
+ mSystemUiProxy.startIntentAndTaskWithLegacyTransition(taskPendingIntent,
+ new Intent(), taskId2, stagePosition == STAGE_POSITION_TOP_OR_LEFT,
+ mainOpts.toBundle(), null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
+ splitRatio, adapter);
+ }
}
}
@@ -156,19 +176,22 @@
*/
private class RemoteSplitLaunchTransitionRunner implements RemoteTransitionRunner {
- private final Task mInitialTask;
- private final Task mSecondTask;
+ private final int mInitialTaskId;
+ private final PendingIntent mInitialTaskPendingIntent;
+ private final int mSecondTaskId;
- RemoteSplitLaunchTransitionRunner(Task initialTask, Task secondTask) {
- mInitialTask = initialTask;
- mSecondTask = secondTask;
+ RemoteSplitLaunchTransitionRunner(int initialTaskId, PendingIntent initialTaskPendingIntent,
+ int secondTaskId) {
+ mInitialTaskId = initialTaskId;
+ mInitialTaskPendingIntent = initialTaskPendingIntent;
+ mSecondTaskId = secondTaskId;
}
@Override
public void startAnimation(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction t, Runnable finishCallback) {
- TaskViewUtils.composeRecentsSplitLaunchAnimator(mInitialTask,
- mSecondTask, info, t, finishCallback);
+ TaskViewUtils.composeRecentsSplitLaunchAnimator(mInitialTaskId,
+ mInitialTaskPendingIntent, mSecondTaskId, info, t, finishCallback);
// After successful launch, call resetState
resetState();
}
@@ -180,14 +203,16 @@
*/
private class RemoteSplitLaunchAnimationRunner implements RemoteAnimationRunnerCompat {
- private final Task mInitialTask;
- private final Task mSecondTask;
+ private final int mInitialTaskId;
+ private final PendingIntent mInitialTaskPendingIntent;
+ private final int mSecondTaskId;
private final Consumer<Boolean> mSuccessCallback;
- RemoteSplitLaunchAnimationRunner(Task initialTask, Task secondTask,
- Consumer<Boolean> successCallback) {
- mInitialTask = initialTask;
- mSecondTask = secondTask;
+ RemoteSplitLaunchAnimationRunner(int initialTaskId, PendingIntent initialTaskPendingIntent,
+ int secondTaskId, Consumer<Boolean> successCallback) {
+ mInitialTaskId = initialTaskId;
+ mInitialTaskPendingIntent = initialTaskPendingIntent;
+ mSecondTaskId = secondTaskId;
mSuccessCallback = successCallback;
}
@@ -197,8 +222,9 @@
Runnable finishedCallback) {
postAsyncCallback(mHandler,
() -> TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(
- mLaunchingTaskView, mInitialTask, mSecondTask, apps, wallpapers,
- nonApps, mStateManager, mDepthController, () -> {
+ mLaunchingTaskView, mInitialTaskId, mInitialTaskPendingIntent,
+ mSecondTaskId, apps, wallpapers, nonApps, mStateManager,
+ mDepthController, () -> {
finishedCallback.run();
if (mSuccessCallback != null) {
mSuccessCallback.accept(true);
@@ -224,8 +250,9 @@
* To be called if split select was cancelled
*/
public void resetState() {
- mInitialTask = null;
- mSecondTask = null;
+ mInitialTaskId = INVALID_TASK_ID;
+ mInitialTaskPendingIntent = null;
+ mSecondTaskId = INVALID_TASK_ID;
mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
mRecentsAnimationRunning = false;
mLaunchingTaskView = null;
@@ -236,6 +263,7 @@
* chosen
*/
public boolean isSplitSelectActive() {
- return mInitialTask != null && mSecondTask == null;
+ return (mInitialTaskId != INVALID_TASK_ID || mInitialTaskPendingIntent != null)
+ && mSecondTaskId == INVALID_TASK_ID;
}
}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
index 18ab3bb..9ae5d25 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
@@ -7,8 +7,10 @@
import android.animation.ValueAnimator;
import android.content.Context;
+import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
@@ -18,7 +20,6 @@
import androidx.annotation.Nullable;
import com.android.launcher3.BaseActivity;
-import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
@@ -30,7 +31,8 @@
import com.android.quickstep.util.MultiValueUpdateListener;
/**
- * Create an instance via {@link #getFloatingTaskView(StatefulActivity, TaskView, RectF)} to
+ * Create an instance via
+ * {@link #getFloatingTaskView(StatefulActivity, View, Bitmap, Drawable, RectF)} to
* which will have the thumbnail from the provided existing TaskView overlaying the taskview itself.
*
* Can then animate the taskview using
@@ -44,7 +46,7 @@
private SplitPlaceholderView mSplitPlaceholderView;
private RectF mStartingPosition;
- private final BaseDraggingActivity mActivity;
+ private final StatefulActivity mActivity;
private final boolean mIsRtl;
private final Rect mOutline = new Rect();
private PagedOrientationHandler mOrientationHandler;
@@ -74,7 +76,8 @@
mSplitPlaceholderView.setAlpha(0);
}
- private void init(StatefulActivity launcher, TaskView originalView, RectF positionOut) {
+ private void init(StatefulActivity launcher, View originalView, @Nullable Bitmap thumbnail,
+ Drawable icon, RectF positionOut) {
mStartingPosition = positionOut;
updateInitialPositionForView(originalView);
final InsettableFrameLayout.LayoutParams lp =
@@ -86,12 +89,12 @@
setPivotY(0);
// Copy bounds of exiting thumbnail into ImageView
- TaskThumbnailView thumbnail = originalView.getThumbnail();
- mImageView.setImageBitmap(thumbnail.getThumbnail());
+ mImageView.setImageBitmap(thumbnail);
mImageView.setVisibility(VISIBLE);
- mOrientationHandler = originalView.getRecentsView().getPagedOrientationHandler();
- mSplitPlaceholderView.setIconView(originalView.getIconView(),
+ RecentsView recentsView = launcher.getOverviewPanel();
+ mOrientationHandler = recentsView.getPagedOrientationHandler();
+ mSplitPlaceholderView.setIcon(icon,
launcher.getDeviceProfile().overviewTaskIconDrawableSizePx);
mSplitPlaceholderView.getIconView().setRotation(mOrientationHandler.getDegreesRotated());
}
@@ -101,21 +104,20 @@
* appearance of {@code originalView}.
*/
public static FloatingTaskView getFloatingTaskView(StatefulActivity launcher,
- TaskView originalView, RectF positionOut) {
+ View originalView, @Nullable Bitmap thumbnail, Drawable icon, RectF positionOut) {
final BaseDragLayer dragLayer = launcher.getDragLayer();
ViewGroup parent = (ViewGroup) dragLayer.getParent();
final FloatingTaskView floatingView = (FloatingTaskView) launcher.getLayoutInflater()
.inflate(R.layout.floating_split_select_view, parent, false);
- floatingView.init(launcher, originalView, positionOut);
+ floatingView.init(launcher, originalView, thumbnail, icon, positionOut);
parent.addView(floatingView);
return floatingView;
}
- public void updateInitialPositionForView(TaskView originalView) {
- View thumbnail = originalView.getThumbnail();
- Rect viewBounds = new Rect(0, 0, thumbnail.getWidth(), thumbnail.getHeight());
- Utilities.getBoundsForViewInDragLayer(mActivity.getDragLayer(), thumbnail, viewBounds,
+ public void updateInitialPositionForView(View originalView) {
+ Rect viewBounds = new Rect(0, 0, originalView.getWidth(), originalView.getHeight());
+ Utilities.getBoundsForViewInDragLayer(mActivity.getDragLayer(), originalView, viewBounds,
true /* ignoreTransform */, null /* recycle */,
mStartingPosition);
mStartingPosition.offset(originalView.getTranslationX(), originalView.getTranslationY());
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 718effe..3ddec26 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -180,8 +180,8 @@
@Override
public void launchTask(@NonNull Consumer<Boolean> callback, boolean freezeTaskList) {
- getRecentsView().getSplitPlaceholder().launchTasks(mTask, mSecondaryTask,
- STAGE_POSITION_TOP_OR_LEFT, callback, freezeTaskList,
+ getRecentsView().getSplitPlaceholder().launchTasks(mTask.key.id, null,
+ mSecondaryTask.key.id, STAGE_POSITION_TOP_OR_LEFT, callback, freezeTaskList,
getSplitRatio());
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index e0395ea..e8f3324 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -34,6 +34,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.popup.QuickstepSystemShortcut;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.SplitConfigurationOptions;
@@ -168,4 +169,10 @@
super.initiateSplitSelect(taskView, stagePosition);
mActivity.getStateManager().goToState(LauncherState.OVERVIEW_SPLIT_SELECT);
}
+
+ @Override
+ public void initiateSplitSelect(QuickstepSystemShortcut.SplitSelectSource splitSelectSource) {
+ super.initiateSplitSelect(splitSelectSource);
+ mActivity.getStateManager().goToState(LauncherState.OVERVIEW_SPLIT_SELECT);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index fcc6272..6a3286b 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -214,12 +214,13 @@
setPadding(mInsets.left, 0, mInsets.right + additionalPadding, 0);
}
- // Align vertically, using taskbar height + mDp.taskbarOffsetY() to guestimate
- // where the button nav top is
+ // Align vertically, using taskbar height + mDp.taskbarOffsetY() to estimate where
+ // the button nav top is.
View startActionView = findViewById(R.id.action_screenshot);
int marginBottom = getOverviewActionsBottomMarginPx(
SysUINavigationMode.getMode(getContext()), mDp);
- int actionsTop = (mDp.heightPx - marginBottom - mInsets.bottom);
+ int actionsTop =
+ (mDp.heightPx - marginBottom - mInsets.bottom) - startActionView.getHeight();
int navTop = mDp.heightPx - (mDp.taskbarSize + mDp.getTaskbarOffsetY());
int transY = navTop - actionsTop
+ ((mDp.taskbarSize - startActionView.getHeight()) / 2);
@@ -296,10 +297,13 @@
return inset;
}
+ // Actions button will be aligned with nav buttons in updatePaddingAndTranslations().
if (mode == SysUINavigationMode.Mode.THREE_BUTTONS) {
return dp.overviewActionsMarginThreeButtonPx + inset;
}
- return dp.overviewActionsBottomMarginGesturePx + inset;
+ // There is no bottom inset when taskbar is present, use stashed taskbar as padding instead.
+ return dp.overviewActionsBottomMarginGesturePx
+ + (dp.isTaskbarPresent ? dp.stashedTaskbarSize : inset);
}
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index aadf67c..2a2d1dd 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -16,6 +16,7 @@
package com.android.quickstep.views;
+import static android.app.PendingIntent.FLAG_MUTABLE;
import static android.view.Surface.ROTATION_0;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;
@@ -27,6 +28,7 @@
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
+import static com.android.launcher3.QuickstepTransitionManager.SPLIT_LAUNCH_DURATION;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import static com.android.launcher3.Utilities.mapToRange;
import static com.android.launcher3.Utilities.squaredHypot;
@@ -67,6 +69,8 @@
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
+import android.app.PendingIntent;
+import android.content.ComponentName;
import android.content.Context;
import android.content.LocusId;
import android.content.res.Configuration;
@@ -128,6 +132,7 @@
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.cache.HandlerRunnable;
+import com.android.launcher3.popup.QuickstepSystemShortcut;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulActivity;
@@ -622,6 +627,9 @@
private final Toast mSplitUnsupportedToast = Toast.makeText(getContext(),
R.string.toast_split_app_unsupported, Toast.LENGTH_SHORT);
+ @Nullable
+ private QuickstepSystemShortcut.SplitSelectSource mSplitSelectSource;
+
/**
* Keeps track of the index of the TaskView that split screen was initialized with so we know
* where to insert it back into list of taskViews in case user backs out of entering split
@@ -2001,6 +2009,22 @@
return null;
}
+ @Nullable
+ private TaskView getTaskViewByComponentName(ComponentName componentName) {
+ if (componentName == null) {
+ return null;
+ }
+
+ for (int i = 0; i < getTaskViewCount(); i++) {
+ TaskView taskView = requireTaskViewAt(i);
+ if (taskView.getItemInfo().getIntent().getComponent().getPackageName().equals(
+ componentName.getPackageName())) {
+ return taskView;
+ }
+ }
+ return null;
+ }
+
public int getRunningTaskIndex() {
TaskView taskView = getRunningTaskView();
return taskView == null ? -1 : indexOfChild(taskView);
@@ -2696,12 +2720,23 @@
mSplitSelectStateController.getActiveSplitStagePosition(), mTempRect);
RectF startingTaskRect = new RectF();
- mSplitHiddenTaskView.setVisibility(INVISIBLE);
- mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
- mSplitHiddenTaskView, startingTaskRect);
- mFirstFloatingTaskView.setAlpha(1);
- mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
- mTempRect, mSplitHiddenTaskView, true /*fadeWithThumbnail*/);
+ if (mSplitHiddenTaskView != null) {
+ mSplitHiddenTaskView.setVisibility(INVISIBLE);
+ mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
+ mSplitHiddenTaskView, mSplitHiddenTaskView.getThumbnail().getThumbnail(),
+ mSplitHiddenTaskView.getIconView().getDrawable(), startingTaskRect);
+ mFirstFloatingTaskView.setAlpha(1);
+ mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
+ mTempRect, mSplitHiddenTaskView, true /*fadeWithThumbnail*/);
+ } else {
+ mSplitSelectSource.view.setVisibility(INVISIBLE);
+ mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
+ mSplitSelectSource.view, null,
+ mSplitSelectSource.drawable, startingTaskRect);
+ mFirstFloatingTaskView.setAlpha(1);
+ mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
+ mTempRect, mSplitSelectSource.view, true /*fadeWithThumbnail*/);
+ }
anim.addEndListener(success -> {
if (success) {
mSplitToast.show();
@@ -3924,20 +3959,40 @@
public void initiateSplitSelect(TaskView taskView, @StagePosition int stagePosition) {
mSplitHiddenTaskView = taskView;
- Rect initialBounds = new Rect(taskView.getLeft(), taskView.getTop(), taskView.getRight(),
- taskView.getBottom());
- mSplitSelectStateController.setInitialTaskSelect(taskView.getTask(),
- stagePosition, initialBounds);
+ mSplitSelectStateController.setInitialTaskSelect(taskView.getTask().key.id,
+ stagePosition);
mSplitHiddenTaskViewIndex = indexOfChild(taskView);
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
finishRecentsAnimation(true, null);
}
}
+ public void initiateSplitSelect(QuickstepSystemShortcut.SplitSelectSource splitSelectSource) {
+ // Remove the task if it exists in Overview
+ TaskView matchingTaskView = getTaskViewByComponentName(
+ splitSelectSource.intent.getComponent());
+ if (matchingTaskView != null) {
+ removeTaskInternal(matchingTaskView.getTaskViewId());
+ }
+
+ mSplitSelectSource = splitSelectSource;
+ mSplitSelectStateController.setInitialTaskSelect(
+ PendingIntent.getActivity(
+ mContext, 0, splitSelectSource.intent, FLAG_MUTABLE),
+ splitSelectSource.position.stagePosition);
+ }
+
public PendingAnimation createSplitSelectInitAnimation() {
- int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext());
- return createTaskDismissAnimation(mSplitHiddenTaskView, true, false, duration,
- true /* dismissingForSplitSelection*/);
+ if (mSplitHiddenTaskView != null) {
+ int duration = mActivity.getStateManager().getState().getTransitionDuration(
+ getContext());
+ return createTaskDismissAnimation(mSplitHiddenTaskView, true, false, duration,
+ true /* dismissingForSplitSelection*/);
+ } else {
+ PendingAnimation anim = new PendingAnimation(SPLIT_LAUNCH_DURATION);
+ createInitialSplitSelectAnimation(anim);
+ return anim;
+ }
}
public void confirmSplitSelect(TaskView taskView) {
@@ -3968,13 +4023,14 @@
false /*fadeWithThumbnail*/);
mSecondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
- taskView, secondTaskStartingBounds);
+ taskView, taskView.getThumbnail().getThumbnail(),
+ taskView.getIconView().getDrawable(), secondTaskStartingBounds);
mSecondFloatingTaskView.setAlpha(1);
mSecondFloatingTaskView.addAnimation(pendingAnimation, secondTaskStartingBounds,
secondTaskEndingBounds, taskView.getThumbnail(),
true /*fadeWithThumbnail*/);
pendingAnimation.addEndListener(aBoolean ->
- mSplitSelectStateController.setSecondTaskId(taskView.getTask(),
+ mSplitSelectStateController.setSecondTaskId(taskView.getTask().key.id,
aBoolean1 -> RecentsView.this.resetFromSplitSelectionState()));
mSecondSplitHiddenTaskView = taskView;
taskView.setVisibility(INVISIBLE);
@@ -3983,6 +4039,20 @@
/** TODO(b/181707736) More gracefully handle exiting split selection state */
protected void resetFromSplitSelectionState() {
+ if (mSplitSelectSource != null || mSplitHiddenTaskViewIndex != -1) {
+ if (mFirstFloatingTaskView != null) {
+ mActivity.getRootView().removeView(mFirstFloatingTaskView);
+ mFirstFloatingTaskView = null;
+ }
+ if (mSecondFloatingTaskView != null) {
+ mActivity.getRootView().removeView(mSecondFloatingTaskView);
+ mSecondFloatingTaskView = null;
+ mSecondSplitHiddenTaskView.setVisibility(VISIBLE);
+ mSecondSplitHiddenTaskView = null;
+ }
+ mSplitSelectSource = null;
+ }
+
if (mSplitHiddenTaskViewIndex == -1) {
return;
}
@@ -4002,16 +4072,6 @@
mSplitHiddenTaskView.setVisibility(VISIBLE);
mSplitHiddenTaskView = null;
}
- if (mFirstFloatingTaskView != null) {
- mActivity.getRootView().removeView(mFirstFloatingTaskView);
- mFirstFloatingTaskView = null;
- }
- if (mSecondFloatingTaskView != null) {
- mActivity.getRootView().removeView(mSecondFloatingTaskView);
- mSecondFloatingTaskView = null;
- mSecondSplitHiddenTaskView.setVisibility(VISIBLE);
- mSecondSplitHiddenTaskView = null;
- }
}
/**
@@ -4237,9 +4297,12 @@
if (isSuccess) {
if (tv.getTaskIds()[1] != -1) {
// TODO(b/194414938): make this part of the animations instead.
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRemoteTargetHandles[0]
- .getTransformParams().getTargetSet().nonApps,
- true /*shown*/, false /*animate*/);
+ TaskViewUtils.createSplitAuxiliarySurfacesAnimator(
+ mRemoteTargetHandles[0].getTransformParams().getTargetSet().nonApps,
+ true /*shown*/, (dividerAnimator) -> {
+ dividerAnimator.start();
+ dividerAnimator.end();
+ });
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && tv.isRunningTask()) {
finishRecentsAnimation(false /* toRecents */, null);
diff --git a/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java b/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
index 04a5761..cfa482f 100644
--- a/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
+++ b/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
@@ -17,6 +17,7 @@
package com.android.quickstep.views;
import android.content.Context;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.view.Gravity;
@@ -52,14 +53,14 @@
return mIconView;
}
- public void setIconView(IconView iconView, int iconSize) {
+ public void setIcon(Drawable drawable, int iconSize) {
if (mIconView == null) {
mIconView = new IconView(getContext());
addView(mIconView);
}
- mIconView.setDrawable(iconView.getDrawable());
+ mIconView.setDrawable(drawable);
mIconView.setDrawableSize(iconSize, iconSize);
- FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(iconView.getLayoutParams());
+ FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(iconSize, iconSize);
params.gravity = Gravity.CENTER;
mIconView.setLayoutParams(params);
}
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 7f9f63e..6df6212 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -33,7 +33,6 @@
android:id="@+id/all_apps_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/search_container_all_apps"
android:clipToPadding="false"
android:paddingTop="@dimen/all_apps_header_top_padding"
android:paddingBottom="@dimen/all_apps_header_bottom_padding"
diff --git a/res/layout/all_apps_content_layout.xml b/res/layout/all_apps_content_layout.xml
deleted file mode 100644
index 5698977..0000000
--- a/res/layout/all_apps_content_layout.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 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.
- -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/apps_list_view_override"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_below="@id/search_container_all_apps"
- android:clipToPadding="false"
- android:descendantFocusability="afterDescendants"
- android:focusable="true"
- android:layout_marginTop="@dimen/all_apps_header_top_padding"
- android:orientation="vertical">
-</LinearLayout>
diff --git a/res/layout/all_apps_fast_scroller.xml b/res/layout/all_apps_fast_scroller.xml
index 5537bc6..f6a6156 100644
--- a/res/layout/all_apps_fast_scroller.xml
+++ b/res/layout/all_apps_fast_scroller.xml
@@ -21,7 +21,7 @@
android:id="@+id/fast_scroller_popup"
style="@style/FastScrollerPopup"
android:layout_alignParentEnd="true"
- android:layout_below="@+id/search_container_all_apps"
+ android:layout_alignTop="@+id/all_apps_header"
android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
<com.android.launcher3.views.RecyclerViewFastScroller
@@ -30,7 +30,7 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
- android:layout_below="@+id/search_container_all_apps"
+ android:layout_alignTop="@+id/all_apps_header"
android:layout_marginEnd="@dimen/fastscroll_end_margin"
launcher:canThumbDetach="true" />
diff --git a/res/layout/all_apps_rv_layout.xml b/res/layout/all_apps_rv_layout.xml
index c353b36..26d8ecc 100644
--- a/res/layout/all_apps_rv_layout.xml
+++ b/res/layout/all_apps_rv_layout.xml
@@ -19,7 +19,6 @@
android:id="@+id/apps_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_below="@id/search_container_all_apps"
android:clipToPadding="false"
android:descendantFocusability="afterDescendants"
android:focusable="true" />
diff --git a/res/layout/all_apps_tabs.xml b/res/layout/all_apps_tabs.xml
index de4a69d..cf68f51 100644
--- a/res/layout/all_apps_tabs.xml
+++ b/res/layout/all_apps_tabs.xml
@@ -20,7 +20,6 @@
android:id="@+id/all_apps_tabs_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_below="@id/search_container_all_apps"
android:layout_gravity="center_horizontal|top"
android:layout_marginTop="@dimen/all_apps_header_pill_height"
android:clipChildren="true"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a6c5ed8..ddc7d10 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -324,6 +324,7 @@
<!-- Taskbar related (placeholders to compile in Launcher3 without Quickstep) -->
<dimen name="taskbar_size">0dp</dimen>
+ <dimen name="taskbar_stashed_size">0dp</dimen>
<dimen name="qsb_widget_height">0dp</dimen>
<dimen name="taskbar_icon_size">44dp</dimen>
<!-- Note that this applies to both sides of all icons, so visible space is double this. -->
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 1a5b321..c456a4d 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -219,6 +219,7 @@
// Whether Taskbar will inset the bottom of apps by taskbarSize.
public boolean isTaskbarPresentInApps;
public int taskbarSize;
+ public int stashedTaskbarSize;
// DragController
public int flingToDeleteThresholdVelocity;
@@ -256,12 +257,7 @@
widthPx = windowBounds.bounds.width();
heightPx = windowBounds.bounds.height();
availableWidthPx = windowBounds.availableSize.x;
- int taskbarInset = isTaskbarPresent
- ? ResourceUtils.getNavbarSize(
- isLandscape ? "navigation_bar_height_landscape" : "navigation_bar_height",
- res)
- : 0;
- availableHeightPx = windowBounds.availableSize.y - taskbarInset;
+ availableHeightPx = windowBounds.availableSize.y;
aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx);
boolean isTallDevice = Float.compare(aspectRatio, TALL_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0;
@@ -283,6 +279,7 @@
if (isTaskbarPresent) {
taskbarSize = res.getDimensionPixelSize(R.dimen.taskbar_size);
+ stashedTaskbarSize = res.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
}
edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
@@ -1154,6 +1151,7 @@
writer.println(prefix + pxToDpStr("hotseatBarSidePaddingEndPx",
hotseatBarSidePaddingEndPx));
writer.println(prefix + "\tnumShownHotseatIcons: " + numShownHotseatIcons);
+ writer.println(prefix + pxToDpStr("hotseatBorderSpace", hotseatBorderSpace));
writer.println(prefix + "\tisQsbInline: " + isQsbInline);
writer.println(prefix + pxToDpStr("qsbWidth", qsbWidth));
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 45a83aa..661aa00 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -41,6 +41,7 @@
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
+import static com.android.launcher3.logging.StatsLogManager.EventEnum;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_ENTRY;
@@ -142,6 +143,8 @@
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
+import com.android.launcher3.logger.LauncherAtom.WorkspaceContainer;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
@@ -1104,14 +1107,23 @@
&& mAllAppsSessionLogId == null) {
// creates new instance ID since new all apps session is started.
mAllAppsSessionLogId = new InstanceIdSequence().newInstanceId();
- getStatsLogManager()
- .logger()
- .log(FeatureFlags.ENABLE_DEVICE_SEARCH.get()
- ? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH
- : LAUNCHER_ALLAPPS_ENTRY);
+ getStatsLogManager().logger().withContainerInfo(
+ ContainerInfo.newBuilder().setWorkspace(
+ WorkspaceContainer.newBuilder().setPageIndex(
+ getWorkspace().getCurrentPage())).build())
+ .log(getAllAppsEntryEvent());
}
}
+ /**
+ * Returns {@link EventEnum} that should be logged when Launcher enters into AllApps state.
+ */
+ protected EventEnum getAllAppsEntryEvent() {
+ return FeatureFlags.ENABLE_DEVICE_SEARCH.get()
+ ? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH
+ : LAUNCHER_ALLAPPS_ENTRY;
+ }
+
@Override
public void onStateSetEnd(LauncherState state) {
super.onStateSetEnd(state);
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 5ef3690..e3aa758 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -105,8 +105,9 @@
resources,
INVALID_RESOURCE_HANDLE) == 2;
if (dp.isTablet || isGesturalMode) {
- newNavInsets.bottom = ResourceUtils.getNavbarSize(
- "navigation_bar_height_landscape", resources);
+ newNavInsets.bottom = dp.isTaskbarPresent
+ ? 0
+ : ResourceUtils.getNavbarSize("navigation_bar_height_landscape", resources);
} else {
int navWidth = ResourceUtils.getNavbarSize("navigation_bar_width", resources);
if (dp.isSeascape()) {
@@ -116,7 +117,9 @@
}
}
} else {
- newNavInsets.bottom = ResourceUtils.getNavbarSize("navigation_bar_height", resources);
+ newNavInsets.bottom = dp.isTaskbarPresent
+ ? 0
+ : ResourceUtils.getNavbarSize("navigation_bar_height", resources);
}
updatedInsetsBuilder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(newNavInsets));
updatedInsetsBuilder.setInsetsIgnoringVisibility(WindowInsets.Type.navigationBars(),
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 070b98e..fb87f88 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -21,6 +21,7 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
+import android.widget.RelativeLayout;
import androidx.core.graphics.ColorUtils;
import androidx.recyclerview.widget.RecyclerView;
@@ -177,6 +178,28 @@
}
@Override
+ protected View replaceRVContainer(boolean showTabs) {
+ View rvContainer = super.replaceRVContainer(showTabs);
+ if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
+ alignParentTop(rvContainer);
+ layoutAboveSearchContainer(rvContainer);
+ } else {
+ layoutBelowSearchContainer(rvContainer);
+ }
+ return rvContainer;
+ }
+
+ @Override
+ void setupHeader() {
+ super.setupHeader();
+ if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
+ alignParentTop(mHeader);
+ } else {
+ layoutBelowSearchContainer(mHeader);
+ }
+ }
+
+ @Override
protected void updateHeaderScroll(int scrolledOffset) {
super.updateHeaderScroll(scrolledOffset);
if (mSearchUiManager.getEditText() == null) {
@@ -202,6 +225,36 @@
@Override
protected int getHeaderBottom() {
+ if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
+ return super.getHeaderBottom();
+ }
return super.getHeaderBottom() + mSearchContainer.getBottom();
}
+
+ private void layoutBelowSearchContainer(View v) {
+ if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) {
+ return;
+ }
+ RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams();
+ layoutParams.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
+ layoutParams.removeRule(RelativeLayout.ABOVE);
+ layoutParams.addRule(RelativeLayout.BELOW, R.id.search_container_all_apps);
+ }
+
+ private void layoutAboveSearchContainer(View v) {
+ if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) {
+ return;
+ }
+ RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams();
+ layoutParams.addRule(RelativeLayout.ABOVE, R.id.search_container_all_apps);
+ }
+
+ private void alignParentTop(View v) {
+ if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) {
+ return;
+ }
+ RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams();
+ layoutParams.removeRule(RelativeLayout.BELOW);
+ layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ }
}
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index 8d03305..2b2c7c5 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -378,8 +378,7 @@
}
@Override
- public void onDropCompleted(View target, DragObject d, boolean success) {
- }
+ public void onDropCompleted(View target, DragObject d, boolean success) {}
@Override
public void setInsets(Rect insets) {
@@ -488,7 +487,7 @@
return mHasWorkApps;
}
- private void replaceRVContainer(boolean showTabs) {
+ protected View replaceRVContainer(boolean showTabs) {
for (AdapterHolder adapterHolder : mAH) {
if (adapterHolder.mRecyclerView != null) {
adapterHolder.mRecyclerView.setLayoutManager(null);
@@ -513,6 +512,7 @@
mWorkManager.detachWorkModeSwitch();
mViewPager = null;
}
+ return newView;
}
public View getRecyclerViewContainer() {
@@ -644,7 +644,9 @@
@Override
public void drawOnScrim(Canvas canvas) {
- if (!mHeader.isHeaderProtectionSupported()) return;
+ if (!mHeader.isHeaderProtectionSupported()) {
+ return;
+ }
mHeaderPaint.setColor(mHeaderColor);
mHeaderPaint.setAlpha((int) (getAlpha() * Color.alpha(mHeaderColor)));
if (mHeaderPaint.getColor() != mScrimColor && mHeaderPaint.getColor() != 0) {
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index 9d1b04e..bcb0d14 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -26,12 +26,14 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
+import android.view.ViewGroup;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
@@ -138,6 +140,15 @@
mWorkModeSwitch = (WorkModeSwitch) mAllApps.getLayoutInflater().inflate(
R.layout.work_mode_fab, mAllApps, false);
}
+ int workFabMarginBottom =
+ mWorkModeSwitch.getResources().getDimensionPixelSize(R.dimen.work_fab_margin);
+ if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
+ workFabMarginBottom <<= 1; // Double margin to add space above search bar.
+ workFabMarginBottom +=
+ mWorkModeSwitch.getResources().getDimensionPixelSize(R.dimen.qsb_widget_height);
+ }
+ ((ViewGroup.MarginLayoutParams) mWorkModeSwitch.getLayoutParams()).bottomMargin =
+ workFabMarginBottom;
if (mWorkModeSwitch.getParent() != mAllApps) {
mAllApps.addView(mWorkModeSwitch);
}
@@ -158,7 +169,6 @@
mWorkModeSwitch = null;
}
-
public WorkAdapterProvider getAdapterProvider() {
return mAdapterProvider;
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index f46022d..99c9bb9 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -92,6 +92,10 @@
public static final BooleanFlag ENABLE_ONE_SEARCH = new DeviceFlag("ENABLE_ONE_SEARCH", false,
"Use homescreen search box to complete allApps searches");
+ public static final BooleanFlag ENABLE_FLOATING_SEARCH_BAR =
+ getDebugFlag("ENABLE_FLOATING_SEARCH_BAR", false,
+ "Keep All Apps search bar at the bottom (but above keyboard if open)");
+
public static final BooleanFlag COLLECT_SEARCH_HISTORY = new DeviceFlag(
"COLLECT_SEARCH_HISTORY", false, "Allow launcher to collect search history for log");
@@ -248,6 +252,10 @@
"ENABLE_ALL_APPS_IN_TASKBAR", true,
"Enables accessing All Apps from the system Taskbar.");
+ public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE = getDebugFlag(
+ "ENABLE_SPLIT_FROM_WORKSPACE", true,
+ "Enable initiating split screen from workspace.");
+
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index a7cfdde..0d2bc37 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -258,6 +258,9 @@
@UiEvent(doc = "User swipes or fling in DOWN direction to close apps drawer.")
LAUNCHER_ALLAPPS_CLOSE_DOWN(569),
+ @UiEvent(doc = "User tap outside apps drawer sheet to close apps drawer.")
+ LAUNCHER_ALLAPPS_CLOSE_TAP_OUTSIDE(941),
+
@UiEvent(doc = "User swipes or fling in UP direction and hold from the bottom bazel area")
LAUNCHER_OVERVIEW_GESTURE(570),
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index 93387ad..e8941e6 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_CLOSE_TAP_OUTSIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORKSPACE_LONGPRESS;
import android.graphics.PointF;
@@ -40,6 +41,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.Workspace;
import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
@@ -155,6 +157,16 @@
&& mLauncher.isInState(ALL_APPS)
&& mLauncher.getDeviceProfile().isTablet) {
mLauncher.getStateManager().goToState(NORMAL);
+ mLauncher.getStatsLogManager().logger()
+ .withSrcState(ALL_APPS.statsLogOrdinal)
+ .withDstState(NORMAL.statsLogOrdinal)
+ .withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
+ .setWorkspace(
+ LauncherAtom.WorkspaceContainer.newBuilder()
+ .setPageIndex(
+ mLauncher.getWorkspace().getCurrentPage()))
+ .build())
+ .log(LAUNCHER_ALLAPPS_CLOSE_TAP_OUTSIDE);
}
return result;
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index f0b4ba0..53c772f 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -16,12 +16,16 @@
package com.android.launcher3.widget;
+import android.annotation.TargetApi;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.Build;
import android.os.Handler;
import android.os.SystemClock;
+import android.os.Trace;
+import android.util.Log;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.view.MotionEvent;
@@ -52,6 +56,8 @@
implements TouchCompleteListener, View.OnLongClickListener,
LocalColorExtractor.Listener {
+ private static final String TAG = "LauncherAppWidgetHostView";
+
// Related to the auto-advancing of widgets
private static final long ADVANCE_INTERVAL = 20000;
private static final long ADVANCE_STAGGER = 250;
@@ -61,6 +67,8 @@
// Maximum duration for which updates can be deferred.
private static final long UPDATE_LOCK_TIMEOUT_MILLIS = 1000;
+ private static final String TRACE_METHOD_NAME = "appwidget load-widget ";
+
private final Rect mTempRect = new Rect();
private final CheckLongPressHelper mLongPressHelper;
protected final Launcher mLauncher;
@@ -88,6 +96,8 @@
/** The drag content height which is only set when the drag content scale is not 1f. */
private int mDragContentHeight = 0;
+ private boolean mTrackingWidgetUpdate = false;
+
public LauncherAppWidgetHostView(Context context) {
super(context);
mLauncher = Launcher.getLauncher(context);
@@ -121,7 +131,25 @@
}
@Override
+ @TargetApi(Build.VERSION_CODES.Q)
+ public void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) {
+ super.setAppWidget(appWidgetId, info);
+ if (!mTrackingWidgetUpdate && Utilities.ATLEAST_Q) {
+ mTrackingWidgetUpdate = true;
+ Trace.beginAsyncSection(TRACE_METHOD_NAME + info.provider, appWidgetId);
+ Log.i(TAG, "App widget created with id: " + appWidgetId);
+ }
+ }
+
+ @Override
+ @TargetApi(Build.VERSION_CODES.Q)
public void updateAppWidget(RemoteViews remoteViews) {
+ if (mTrackingWidgetUpdate && remoteViews != null && Utilities.ATLEAST_Q) {
+ Log.i(TAG, "App widget with id: " + getAppWidgetId() + " loaded");
+ Trace.endAsyncSection(
+ TRACE_METHOD_NAME + getAppWidgetInfo().provider, getAppWidgetId());
+ mTrackingWidgetUpdate = false;
+ }
if (isDeferringUpdates()) {
mDeferredRemoteViews = remoteViews;
return;
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 5511770..c22b4da 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -98,7 +98,7 @@
public final class LauncherInstrumentation {
private static final String TAG = "Tapl";
- private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 20;
+ private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 15;
private static final int GESTURE_STEP_MS = 16;
private static final long FORCE_PAUSE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(2);