Merge "Restricts the width of pin widget dialog to 89% on large screen devices" into sc-v2-dev
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 475f061..ecd38b4 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -37,7 +37,9 @@
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.CancellationSignal;
+import android.os.Handler;
import android.os.IBinder;
+import android.util.Log;
import android.view.View;
import android.window.SplashScreen;
@@ -89,6 +91,11 @@
public abstract class BaseQuickstepLauncher extends Launcher
implements NavigationModeChangeListener {
+ private static final long BACKOFF_MILLIS = 1000;
+
+ // Max backoff caps at 5 mins
+ private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000;
+
private DepthController mDepthController = new DepthController(this);
private QuickstepTransitionManager mAppTransitionManager;
@@ -108,12 +115,24 @@
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mTaskbarManager = ((TISBinder) iBinder).getTaskbarManager();
mTaskbarManager.setLauncher(BaseQuickstepLauncher.this);
+ Log.d(TAG, "TIS service connected");
+ resetServiceBindRetryState();
}
@Override
public void onServiceDisconnected(ComponentName componentName) { }
+
+ @Override
+ public void onBindingDied(ComponentName name) {
+ Log.w(TAG, "TIS binding died");
+ internalBindToTIS();
+ }
};
+
+ private final Runnable mConnectionRunnable = this::internalBindToTIS;
+ private short mConnectionAttempts;
private final TaskbarStateHandler mTaskbarStateHandler = new TaskbarStateHandler(this);
+ private final Handler mHandler = new Handler();
// Will be updated when dragging from taskbar.
private @Nullable DragOptions mNextWorkspaceDragOptions = null;
@@ -132,11 +151,11 @@
SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this);
-
unbindService(mTisBinderConnection);
if (mTaskbarManager != null) {
mTaskbarManager.clearLauncher(this);
}
+ resetServiceBindRetryState();
super.onDestroy();
}
@@ -264,8 +283,33 @@
mAppTransitionManager = new QuickstepTransitionManager(this);
mAppTransitionManager.registerRemoteAnimations();
- bindService(new Intent(this, TouchInteractionService.class), mTisBinderConnection, 0);
+ internalBindToTIS();
+ }
+ /**
+ * Binds {@link #mTisBinderConnection} to {@link TouchInteractionService}. If the binding fails,
+ * attempts to retry via {@link #mConnectionRunnable}
+ */
+ private void internalBindToTIS() {
+ boolean bound = bindService(new Intent(this, TouchInteractionService.class),
+ mTisBinderConnection, 0);
+ if (bound) {
+ resetServiceBindRetryState();
+ return;
+ }
+
+ Log.w(TAG, "Retrying TIS Binder connection attempt: " + mConnectionAttempts);
+ final long timeoutMs = (long) Math.min(
+ Math.scalb(BACKOFF_MILLIS, mConnectionAttempts), MAX_BACKOFF_MILLIS);
+ mHandler.postDelayed(mConnectionRunnable, timeoutMs);
+ mConnectionAttempts++;
+ }
+
+ private void resetServiceBindRetryState() {
+ if (mHandler.hasCallbacks(mConnectionRunnable)) {
+ mHandler.removeCallbacks(mConnectionRunnable);
+ }
+ mConnectionAttempts = 0;
}
public void setTaskbarUIController(LauncherTaskbarUIController taskbarUIController) {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index c04d15f..096ac6c 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -387,8 +387,11 @@
mGestureState.runOnceAtState(STATE_RECENTS_ANIMATION_CANCELED, () -> {
ThumbnailData snapshot = mGestureState.consumeRecentsAnimationCanceledSnapshot();
if (snapshot != null) {
- mRecentsView.switchToScreenshot(snapshot,
- () -> mRecentsAnimationController.cleanupScreenshot());
+ mRecentsView.switchToScreenshot(snapshot, () -> {
+ if (mRecentsAnimationController != null) {
+ mRecentsAnimationController.cleanupScreenshot();
+ }
+ });
mRecentsView.onRecentsAnimationComplete();
}
});
@@ -740,6 +743,8 @@
mRecentsAnimationStartCallbacks.clear();
}
+ TaskViewUtils.setDividerBarShown(mRecentsAnimationTargets.nonApps, false);
+
// Only add the callback to enable the input consumer after we actually have the controller
mStateCallback.runOnceAtState(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED,
mRecentsAnimationController::enableInputConsumer);
@@ -754,6 +759,8 @@
mActivityInitListener.unregister();
mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
+ TaskViewUtils.setDividerBarShown(mRecentsAnimationTargets.nonApps, true);
+
// Defer clearing the controller and the targets until after we've updated the state
mRecentsAnimationController = null;
mRecentsAnimationTargets = null;
@@ -882,6 +889,7 @@
break;
case LAST_TASK:
mStateCallback.setState(STATE_RESUME_LAST_TASK);
+ TaskViewUtils.setDividerBarShown(mRecentsAnimationTargets.nonApps, true);
break;
}
ActiveGestureLog.INSTANCE.addLog("onSettledOnEndTarget " + endTarget);
@@ -1723,6 +1731,9 @@
@Override
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
+ if (!controller.getFinishTargetIsLauncher()) {
+ TaskViewUtils.setDividerBarShown(mRecentsAnimationTargets.nonApps, true);
+ }
mRecentsAnimationController = null;
mRecentsAnimationTargets = null;
if (mRecentsView != null) {
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index a21c714..239233b 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -19,6 +19,7 @@
import android.graphics.Rect;
import android.util.ArraySet;
+import android.view.RemoteAnimationTarget;
import androidx.annotation.BinderThread;
import androidx.annotation.UiThread;
@@ -39,6 +40,7 @@
com.android.systemui.shared.system.RecentsAnimationListener {
private final Set<RecentsAnimationListener> mListeners = new ArraySet<>();
+ private final SystemUiProxy mSystemUiProxy;
private final boolean mAllowMinimizeSplitScreen;
// TODO(141886704): Remove these references when they are no longer needed
@@ -46,7 +48,9 @@
private boolean mCancelled;
- public RecentsAnimationCallbacks(boolean allowMinimizeSplitScreen) {
+ public RecentsAnimationCallbacks(SystemUiProxy systemUiProxy,
+ boolean allowMinimizeSplitScreen) {
+ mSystemUiProxy = systemUiProxy;
mAllowMinimizeSplitScreen = allowMinimizeSplitScreen;
}
@@ -89,8 +93,11 @@
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
Rect homeContentInsets, Rect minimizedHomeBounds) {
+ RemoteAnimationTarget[] nonAppTargets =
+ mSystemUiProxy.onGoingToRecentsLegacy(mCancelled);
RecentsAnimationTargets targets = new RecentsAnimationTargets(appTargets,
- wallpaperTargets, homeContentInsets, minimizedHomeBounds);
+ wallpaperTargets, RemoteAnimationTargetCompat.wrap(nonAppTargets),
+ homeContentInsets, minimizedHomeBounds);
mController = new RecentsAnimationController(animationController,
mAllowMinimizeSplitScreen, this::onAnimationFinished);
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
index 3861bab..b6d9016 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
@@ -31,9 +31,9 @@
public final Rect minimizedHomeBounds;
public RecentsAnimationTargets(RemoteAnimationTargetCompat[] apps,
- RemoteAnimationTargetCompat[] wallpapers, Rect homeContentInsets,
- Rect minimizedHomeBounds) {
- super(apps, wallpapers, new RemoteAnimationTargetCompat[0], MODE_CLOSING);
+ RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps,
+ Rect homeContentInsets, Rect minimizedHomeBounds) {
+ super(apps, wallpapers, nonApps, MODE_CLOSING);
this.homeContentInsets = homeContentInsets;
this.minimizedHomeBounds = minimizedHomeBounds;
}
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 090fd01..d6b95c1 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -33,6 +33,8 @@
import android.os.UserHandle;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.RemoteAnimationAdapter;
+import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import com.android.launcher3.util.MainThreadInitializedObject;
@@ -562,6 +564,22 @@
}
}
+ /**
+ * Start multiple tasks in split-screen simultaneously.
+ */
+ public void startTasksWithLegacyTransition(int mainTaskId, Bundle mainOptions, int sideTaskId,
+ Bundle sideOptions, @SplitConfigurationOptions.StagePosition int sidePosition,
+ RemoteAnimationAdapter adapter) {
+ if (mSystemUiProxy != null) {
+ try {
+ mSplitScreen.startTasksWithLegacyTransition(mainTaskId, mainOptions, sideTaskId,
+ sideOptions, sidePosition, adapter);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call startTasksWithLegacyTransition");
+ }
+ }
+ }
+
public void startShortcut(String packageName, String shortcutId, int stage, int position,
Bundle options, UserHandle user) {
if (mSplitScreen != null) {
@@ -595,6 +613,24 @@
}
}
+ /**
+ * Call this when going to recents so that shell can set-up and provide appropriate leashes
+ * for animation (eg. DividerBar).
+ *
+ * @param cancel true if recents starting is being cancelled.
+ * @return RemoteAnimationTargets of windows that need to animate but only exist in shell.
+ */
+ public RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel) {
+ if (mSplitScreen != null) {
+ try {
+ return mSplitScreen.onGoingToRecentsLegacy(cancel);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call onGoingToRecentsLegacy");
+ }
+ }
+ return null;
+ }
+
//
// One handed
//
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 33718a3..fe07cbd 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -109,7 +109,8 @@
final BaseActivityInterface activityInterface = gestureState.getActivityInterface();
mLastGestureState = gestureState;
- mCallbacks = new RecentsAnimationCallbacks(activityInterface.allowMinimizeSplitScreen());
+ mCallbacks = new RecentsAnimationCallbacks(SystemUiProxy.INSTANCE.get(mCtx),
+ activityInterface.allowMinimizeSplitScreen());
mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 37fda73..f292f1a 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.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -405,77 +406,39 @@
}
/** Legacy version (until shell transitions are enabled) */
- public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull AnimatorSet anim,
+ public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull TaskView initialView,
@NonNull TaskView v, @NonNull RemoteAnimationTargetCompat[] appTargets,
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
- @NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing,
- @NonNull StateManager stateManager, @NonNull DepthController depthController,
- int targetStage) {
- PendingAnimation out = new PendingAnimation(RECENTS_LAUNCH_DURATION);
- boolean isRunningTask = v.isRunningTask();
- TransformParams params = null;
- TaskViewSimulator tvs = null;
- RecentsView recentsView = v.getRecentsView();
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask) {
- params = recentsView.getLiveTileParams();
- tvs = recentsView.getLiveTileTaskViewSimulator();
+ @NonNull RemoteAnimationTargetCompat[] nonAppTargets,
+ @NonNull Runnable finishCallback) {
+
+ final int[] splitRoots = new int[2];
+ for (int i = 0; i < appTargets.length; ++i) {
+ final int taskId = appTargets[i].taskInfo != null ? appTargets[i].taskInfo.taskId : -1;
+ final int mode = appTargets[i].mode;
+ if (taskId == initialView.getTask().key.id || taskId == v.getTask().key.id) {
+ if (mode != MODE_OPENING) {
+ throw new IllegalStateException(
+ "Expected task to be opening, but it is " + mode);
+ }
+ splitRoots[taskId == initialView.getTask().key.id ? 0 : 1] = i;
+ }
}
- boolean inLiveTileMode =
- ENABLE_QUICKSTEP_LIVE_TILE.get() && recentsView.getRunningTaskIndex() != -1;
- final RemoteAnimationTargets targets =
- new RemoteAnimationTargets(appTargets, wallpaperTargets, nonAppTargets,
- inLiveTileMode ? MODE_CLOSING : MODE_OPENING);
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- if (params == null) {
- SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
- targets.addReleaseCheck(applier);
-
- params = new TransformParams()
- .setSyncTransactionApplier(applier)
- .setTargetSet(targets);
+ // 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(appTargets[splitRoots[i]].leash.getSurfaceControl());
+ t.setAlpha(appTargets[splitRoots[i]].leash.getSurfaceControl(), 1.f);
}
- Rect crop = new Rect();
- Context context = v.getContext();
- DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
- if (tvs == null && targets.apps.length > 0) {
- tvs = new TaskViewSimulator(recentsView.getContext(), recentsView.getSizeStrategy());
- tvs.setDp(dp);
+ // This contains the initial state (before animation), so apply this at the beginning of
+ // the animation.
+ t.apply();
- // RecentsView never updates the display rotation until swipe-up so the value may
- // be stale. Use the display value instead.
- int displayRotation = DisplayController.INSTANCE.get(recentsView.getContext())
- .getInfo().rotation;
- tvs.getOrientationState().update(displayRotation, displayRotation);
-
- tvs.setPreview(targets.apps[targets.apps.length - 1]);
- tvs.fullScreenProgress.value = 0;
- tvs.recentsViewScale.value = 1;
-// tvs.setScroll(startScroll);
-
- // Fade in the task during the initial 20% of the animation
- out.addFloat(params, TransformParams.TARGET_ALPHA, 0, 1,
- clampToProgress(LINEAR, 0, 0.2f));
- }
-
- TaskViewSimulator topMostSimulator = null;
-
- if (tvs != null) {
- out.setFloat(tvs.fullScreenProgress,
- AnimatedFloat.VALUE, 1, TOUCH_RESPONSE_INTERPOLATOR);
- out.setFloat(tvs.recentsViewScale,
- AnimatedFloat.VALUE, tvs.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR);
- out.setFloat(tvs.recentsViewScroll,
- AnimatedFloat.VALUE, 0, TOUCH_RESPONSE_INTERPOLATOR);
-
- TaskViewSimulator finalTsv = tvs;
- TransformParams finalParams = params;
- out.addOnFrameCallback(() -> finalTsv.apply(finalParams));
- topMostSimulator = tvs;
- }
-
- anim.play(out.buildAnim());
+ // Once there is an animation, this should be called AFTER the animation completes.
+ finishCallback.run();
}
public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
@@ -490,6 +453,10 @@
PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
createRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets,
nonAppTargets, depthController, pa);
+ if (launcherClosing) {
+ // TODO(b/182592057): differentiate between "restore split" vs "launch fullscreen app"
+ TaskViewUtils.setDividerBarShown(nonAppTargets, true);
+ }
Animator childStateAnimation = null;
// Found a visible recents task that matches the opening app, lets launch the app from there
@@ -542,4 +509,19 @@
stateManager.setCurrentAnimation(anim, childStateAnimation);
anim.addListener(windowAnimEndListener);
}
+
+ static void setDividerBarShown(RemoteAnimationTargetCompat[] nonApps, boolean shown) {
+ // TODO(b/182592057): make this part of the animations instead.
+ if (nonApps != null && nonApps.length > 0) {
+ for (int i = 0; i < nonApps.length; ++i) {
+ final RemoteAnimationTargetCompat targ = nonApps[i];
+ if (targ.windowType == TYPE_DOCK_DIVIDER) {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.setVisibility(targ.leash.getSurfaceControl(), shown);
+ t.apply();
+ t.close();
+ }
+ }
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index a147b68..2351a4e 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -22,33 +22,26 @@
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
-import android.animation.AnimatorSet;
-import android.app.ActivityOptions;
+import android.app.ActivityThread;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
-import android.util.Pair;
import android.view.Gravity;
+import android.view.RemoteAnimationAdapter;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import androidx.annotation.Nullable;
-import com.android.launcher3.BaseActivity;
-import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InsettableFrameLayout;
-import com.android.launcher3.LauncherAnimationRunner;
-import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
import com.android.launcher3.R;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskAnimationManager;
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.views.TaskView;
-import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -92,37 +85,27 @@
? new int[]{mInitialTaskView.getTask().key.id, taskView.getTask().key.id}
: new int[]{taskView.getTask().key.id, mInitialTaskView.getTask().key.id};
- RemoteSplitLaunchAnimationRunner animationRunner =
- new RemoteSplitLaunchAnimationRunner(mInitialTaskView, taskView);
+ RemoteSplitLaunchTransitionRunner animationRunner =
+ new RemoteSplitLaunchTransitionRunner(mInitialTaskView, taskView);
mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR));
- return;
+ } else {
+ // Assume initial task is for top/left part of screen
+ final int[] taskIds = mInitialPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT
+ ? new int[]{mInitialTaskView.getTask().key.id, taskView.getTask().key.id}
+ : new int[]{taskView.getTask().key.id, mInitialTaskView.getTask().key.id};
+
+ RemoteSplitLaunchAnimationRunner animationRunner =
+ new RemoteSplitLaunchAnimationRunner(mInitialTaskView, taskView);
+ final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+ RemoteAnimationAdapterCompat.wrapRemoteAnimationRunner(animationRunner),
+ 300, 150,
+ ActivityThread.currentActivityThread().getApplicationThread());
+
+ mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], null /* mainOptions */,
+ taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, adapter);
}
- // Assume initial mInitialTaskId is for top/left part of screen
- RemoteAnimationFactory initialSplitRunnerWrapped = new SplitLaunchAnimationRunner(
- mInitialTaskView, 0);
- RemoteAnimationFactory secondarySplitRunnerWrapped = new SplitLaunchAnimationRunner(
- taskView, 1);
- RemoteAnimationRunnerCompat initialSplitRunner = new LauncherAnimationRunner(
- new Handler(Looper.getMainLooper()), initialSplitRunnerWrapped,
- true /* startAtFrontOfQueue */);
- RemoteAnimationRunnerCompat secondarySplitRunner = new LauncherAnimationRunner(
- new Handler(Looper.getMainLooper()), secondarySplitRunnerWrapped,
- true /* startAtFrontOfQueue */);
- ActivityOptions initialOptions = ActivityOptionsCompat.makeRemoteAnimation(
- new RemoteAnimationAdapterCompat(initialSplitRunner, 300, 150));
- ActivityOptions secondaryOptions = ActivityOptionsCompat.makeRemoteAnimation(
- new RemoteAnimationAdapterCompat(secondarySplitRunner, 300, 150));
- mSystemUiProxy.startTask(mInitialTaskView.getTask().key.id, mInitialPosition.mStageType,
- mInitialPosition.mStagePosition,
- /*null*/ initialOptions.toBundle());
- Pair<Integer, Integer> compliment = getComplimentaryStageAndPosition(mInitialPosition);
- mSystemUiProxy.startTask(taskView.getTask().key.id, compliment.first,
- compliment.second,
- /*null*/ secondaryOptions.toBundle());
- // After successful launch, call resetState
- resetState();
}
/**
@@ -153,12 +136,12 @@
/**
* Requires Shell Transitions
*/
- private class RemoteSplitLaunchAnimationRunner implements RemoteTransitionRunner {
+ private class RemoteSplitLaunchTransitionRunner implements RemoteTransitionRunner {
private final TaskView mInitialTaskView;
private final TaskView mTaskView;
- RemoteSplitLaunchAnimationRunner(TaskView initialTaskView, TaskView taskView) {
+ RemoteSplitLaunchTransitionRunner(TaskView initialTaskView, TaskView taskView) {
mInitialTaskView = initialTaskView;
mTaskView = taskView;
}
@@ -175,48 +158,34 @@
/**
* LEGACY
- * @return the opposite stage and position from the {@param position} provided as first and
- * second object, respectively
- * Ex. If position is has stage = Main and position = Top/Left, this will return
- * Pair(stage=Side, position=Bottom/Left)
- */
- private Pair<Integer, Integer> getComplimentaryStageAndPosition(SplitPositionOption position) {
- // Right now this is as simple as flipping between 0 and 1
- int complimentStageType = position.mStageType ^ 1;
- int complimentStagePosition = position.mStagePosition ^ 1;
- return new Pair<>(complimentStageType, complimentStagePosition);
- }
-
- /**
- * LEGACY
* Remote animation runner for animation to launch an app.
*/
- private class SplitLaunchAnimationRunner implements RemoteAnimationFactory {
+ private class RemoteSplitLaunchAnimationRunner implements RemoteAnimationRunnerCompat {
- private final TaskView mV;
- private final int mTargetState;
+ private final TaskView mInitialTaskView;
+ private final TaskView mTaskView;
- SplitLaunchAnimationRunner(TaskView v, int targetState) {
- mV = v;
- mTargetState = targetState;
+ RemoteSplitLaunchAnimationRunner(TaskView initialTaskView, TaskView taskView) {
+ mInitialTaskView = initialTaskView;
+ mTaskView = taskView;
}
@Override
- public void onCreateAnimation(int transit,
- RemoteAnimationTargetCompat[] appTargets,
- RemoteAnimationTargetCompat[] wallpaperTargets,
- RemoteAnimationTargetCompat[] nonAppTargets,
- LauncherAnimationRunner.AnimationResult result) {
- AnimatorSet anim = new AnimatorSet();
- BaseQuickstepLauncher activity = BaseActivity.fromContext(mV.getContext());
- TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(anim, mV,
- appTargets, wallpaperTargets, nonAppTargets, true, activity.getStateManager(),
- activity.getDepthController(), mTargetState);
- result.setAnimation(anim, activity);
+ public void onAnimationStart(int transit, RemoteAnimationTargetCompat[] apps,
+ RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps,
+ Runnable finishedCallback) {
+ TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTaskView, mTaskView, apps,
+ wallpapers, nonApps, finishedCallback);
+ // After successful launch, call resetState
+ resetState();
+ }
+
+ @Override
+ public void onAnimationCancelled() {
+ resetState();
}
}
-
/**
* To be called if split select was cancelled
*/
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 0103acf..897dfbe 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -82,6 +82,7 @@
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.FloatProperty;
+import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
@@ -128,8 +129,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.SplitConfigurationOptions;
import com.android.launcher3.util.RunnableList;
+import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TranslateEdgeEffect;
@@ -988,6 +989,7 @@
@Override
protected void onPageBeginTransition() {
super.onPageBeginTransition();
+ Log.d("b/193125090", "Disabling ActionsView due to scrolling");
mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, true);
}
@@ -995,7 +997,10 @@
protected void onPageEndTransition() {
super.onPageEndTransition();
if (isClearAllHidden()) {
+ Log.d("b/193125090", "Enabling ActionsView due after scrolling");
mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, false);
+ } else {
+ Log.d("b/193125090", "Not enabling ActionsView due to ClearAll not hidden");
}
if (getNextPage() > 0) {
setSwipeDownShouldLaunchApp(true);
@@ -1159,6 +1164,7 @@
}
if (mFocusedTaskId == -1 && getTaskViewCount() > 0) {
mFocusedTaskId = getTaskViewAt(0).getTaskId();
+ Log.d("b/193125090", "applyLoadPlan - mFocusedTaskId: " + mFocusedTaskId);
}
updateTaskSize();
@@ -1475,14 +1481,22 @@
}
private void updateActionsViewScrollAlpha() {
+ Log.d("b/193125090", "updateActionsViewScrollAlpha - showAsGrid: " + showAsGrid());
float scrollAlpha = 1f;
if (showAsGrid()) {
TaskView focusedTaskView = getFocusedTaskView();
+ Log.d("b/193125090",
+ "updateActionsViewScrollAlpha - focusedTaskView: " + focusedTaskView);
if (focusedTaskView != null) {
float scrollDiff = Math.abs(getScrollForPage(indexOfChild(focusedTaskView))
- mOrientationHandler.getPrimaryScroll(this));
float delta = (mGridSideMargin - scrollDiff) / (float) mGridSideMargin;
scrollAlpha = Utilities.boundToRange(delta, 0, 1);
+ Log.d("b/193125090",
+ "updateActionsViewScrollAlpha - focusedTaskScroll: " + getScrollForPage(
+ indexOfChild(focusedTaskView)) + ", primaryScroll: "
+ + mOrientationHandler.getPrimaryScroll(this) + ", mGridSideMargin: "
+ + mGridSideMargin);
}
}
mActionsView.getScrollAlpha().setValue(scrollAlpha);
@@ -2742,6 +2756,7 @@
@Override
public void setVisibility(int visibility) {
+ Log.d("b/193125090", "setVisibility: " + visibility);
super.setVisibility(visibility);
if (mActionsView != null) {
mActionsView.updateHiddenFlags(HIDDEN_NO_RECENTS, visibility != VISIBLE);
diff --git a/res/drawable/work_card.xml b/res/drawable/work_card.xml
index 7048955..4a66cac 100644
--- a/res/drawable/work_card.xml
+++ b/res/drawable/work_card.xml
@@ -19,6 +19,6 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
<solid android:color="?androidprv:attr/colorSurface" />
- <corners android:radius="@dimen/work_edu_card_margin" />
+ <corners android:radius="@dimen/work_edu_card_radius" />
</shape>
diff --git a/res/layout/add_item_confirmation_activity.xml b/res/layout/add_item_confirmation_activity.xml
index 1aeda50..6fd4a85 100644
--- a/res/layout/add_item_confirmation_activity.xml
+++ b/res/layout/add_item_confirmation_activity.xml
@@ -65,12 +65,19 @@
android:alpha="0.7"
android:importantForAccessibility="no"/>
- <include layout="@layout/widget_cell"
- android:id="@+id/widget_cell"
+ <ScrollView
+ android:id="@+id/widget_preview_scroll_view"
android:layout_width="match_parent"
android:layout_height="0dp"
- android:layout_weight="1"
- android:layout_marginVertical="16dp" />
+ android:layout_marginVertical="16dp"
+ android:layout_weight="1">
+
+ <include
+ android:id="@+id/widget_cell"
+ layout="@layout/widget_cell"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </ScrollView>
<LinearLayout
android:layout_width="match_parent"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9a49e8a..a4a562e 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -120,13 +120,14 @@
<!-- Floating action button inside work tab to toggle work profile -->
<dimen name="work_fab_height">56dp</dimen>
- <dimen name="work_fab_radius">24dp</dimen>
+ <dimen name="work_fab_radius">28dp</dimen>
<dimen name="work_card_padding_horizontal">24dp</dimen>
<dimen name="work_card_padding_vertical">32dp</dimen>
<dimen name="work_fab_margin">16dp</dimen>
<dimen name="work_profile_footer_padding">20dp</dimen>
<dimen name="work_profile_footer_text_size">16sp</dimen>
<dimen name="work_edu_card_margin">16dp</dimen>
+ <dimen name="work_edu_card_radius">28dp</dimen>
<!-- rounded button shown inside card views, and snack bars -->
<dimen name="padded_rounded_button_height">48dp</dimen>
diff --git a/robolectric_tests/src/com/android/launcher3/widget/CachingWidgetPreviewLoaderTest.java b/robolectric_tests/src/com/android/launcher3/widget/CachingWidgetPreviewLoaderTest.java
index c18e26c..1090d1e 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/CachingWidgetPreviewLoaderTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/CachingWidgetPreviewLoaderTest.java
@@ -52,15 +52,15 @@
@RunWith(RobolectricTestRunner.class)
public class CachingWidgetPreviewLoaderTest {
- private static final Size SIZE_10_10 = new Size(10, 10);
- private static final Size SIZE_20_20 = new Size(20, 20);
+ private final Size SIZE_10_10 = new Size(10, 10);
+ private final Size SIZE_20_20 = new Size(20, 20);
private static final String TEST_PACKAGE = "com.example.test";
- private static final ComponentName TEST_PROVIDER =
+ private final ComponentName TEST_PROVIDER =
new ComponentName(TEST_PACKAGE, ".WidgetProvider");
- private static final ComponentName TEST_PROVIDER2 =
+ private final ComponentName TEST_PROVIDER2 =
new ComponentName(TEST_PACKAGE, ".WidgetProvider2");
- private static final Bitmap BITMAP = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
- private static final Bitmap BITMAP2 = Bitmap.createBitmap(20, 20, Bitmap.Config.ARGB_8888);
+ private final Bitmap BITMAP = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
+ private final Bitmap BITMAP2 = Bitmap.createBitmap(20, 20, Bitmap.Config.ARGB_8888);
@Mock private CancellationSignal mCancellationSignal;
diff --git a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
index 1324539..b92c476 100644
--- a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
@@ -26,10 +26,12 @@
import android.graphics.Insets;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.WindowInsets;
+import android.widget.ScrollView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
@@ -45,6 +47,7 @@
private static final int DEFAULT_CLOSE_DURATION = 200;
private final Rect mInsets;
+ private ScrollView mWidgetPreviewScrollView;
public AddItemWidgetsBottomSheet(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -69,6 +72,19 @@
}
@Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ mNoIntercept = false;
+ // Suppress drag to dismiss gesture if the scroll view is being scrolled.
+ if (getPopupContainer().isEventOverView(mWidgetPreviewScrollView, ev)
+ && mWidgetPreviewScrollView.getScrollY() > 0) {
+ mNoIntercept = true;
+ }
+ }
+ return super.onControllerInterceptTouchEvent(ev);
+ }
+
+ @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int width = r - l;
int height = b - t;
@@ -114,6 +130,7 @@
protected void onFinishInflate() {
super.onFinishInflate();
mContent = findViewById(R.id.add_item_bottom_sheet_content);
+ mWidgetPreviewScrollView = findViewById(R.id.widget_preview_scroll_view);
}
private void animateOpen() {
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 4338ed0..adc7ba0 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -51,6 +51,8 @@
public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
implements OnClickListener, OnLongClickListener, DragSource,
PopupDataProvider.PopupDataChangeListener, Insettable {
+ /** The default number of cells that can fit horizontally in a widget sheet. */
+ protected static final int DEFAULT_MAX_HORIZONTAL_SPANS = 4;
/**
* The maximum scale, [0, 1], of the device screen width that the widgets picker can consume
* on large screen devices.
@@ -152,6 +154,17 @@
MeasureSpec.getSize(heightMeasureSpec));
}
+ /** Returns the number of cells that can fit horizontally in a given {@code content}. */
+ protected int computeMaxHorizontalSpans(View content, int contentHorizontalPaddingPx) {
+ DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
+ int availableWidth = content.getMeasuredWidth() - contentHorizontalPaddingPx;
+ Point cellSize = deviceProfile.getCellSize();
+ if (cellSize.x > 0) {
+ return availableWidth / cellSize.x;
+ }
+ return DEFAULT_MAX_HORIZONTAL_SPANS;
+ }
+
private boolean beginDraggingWidget(WidgetCell v) {
// Get the widget preview as the drag representation
WidgetImageView image = v.getWidgetView();
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index c045cf1..14aeaf6 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -70,9 +70,11 @@
private static final int DEFAULT_CLOSE_DURATION = 200;
private static final long EDUCATION_TIP_DELAY_MS = 300;
+ private final int mWidgetSheetContentHorizontalPadding;
+
private ItemInfo mOriginalItemInfo;
private final int mMaxTableHeight;
- private int mMaxHorizontalSpan = 4;
+ private int mMaxHorizontalSpan = DEFAULT_MAX_HORIZONTAL_SPANS;
private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
new OnLayoutChangeListener() {
@@ -117,6 +119,9 @@
if (!hasSeenEducationTip()) {
addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
}
+
+ mWidgetSheetContentHorizontalPadding = getResources().getDimensionPixelSize(
+ R.dimen.widget_list_horizontal_margin);
}
@Override
@@ -137,10 +142,8 @@
private boolean updateMaxSpansPerRow() {
if (getMeasuredWidth() == 0) return false;
- int paddingPx = 2 * getResources().getDimensionPixelOffset(
- R.dimen.widget_cell_horizontal_padding);
- int maxHorizontalSpan = findViewById(R.id.widgets_table).getMeasuredWidth()
- / (mActivityContext.getDeviceProfile().cellWidthPx + paddingPx);
+ int maxHorizontalSpan = computeMaxHorizontalSpans(mContent,
+ mWidgetSheetContentHorizontalPadding);
if (mMaxHorizontalSpan != maxHorizontalSpan) {
// Ensure the table layout is showing widgets in the right column after measure.
mMaxHorizontalSpan = maxHorizontalSpan;
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 6c2cca6..5e1a534 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -25,6 +25,7 @@
import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Process;
import android.os.UserHandle;
@@ -148,13 +149,13 @@
private final int mTabsHeight;
private final int mViewPagerTopPadding;
private final int mSearchAndRecommendationContainerBottomMargin;
- private final int mWidgetCellHorizontalPadding;
+ private final int mWidgetSheetContentHorizontalPadding;
@Nullable private WidgetsRecyclerView mCurrentWidgetsRecyclerView;
@Nullable private PersonalWorkPagedView mViewPager;
private boolean mIsInSearchMode;
private boolean mIsNoWidgetsViewNeeded;
- private int mMaxSpansPerRow = 4;
+ private int mMaxSpansPerRow = DEFAULT_MAX_HORIZONTAL_SPANS;
private View mTabsView;
private TextView mNoWidgetsView;
private SearchAndRecommendationViewHolder mSearchAndRecommendationViewHolder;
@@ -166,19 +167,20 @@
mAdapters.put(AdapterHolder.PRIMARY, new AdapterHolder(AdapterHolder.PRIMARY));
mAdapters.put(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK));
mAdapters.put(AdapterHolder.SEARCH, new AdapterHolder(AdapterHolder.SEARCH));
+
+ Resources resources = getResources();
mTabsHeight = mHasWorkProfile
- ? getContext().getResources()
- .getDimensionPixelSize(R.dimen.all_apps_header_pill_height)
+ ? resources.getDimensionPixelSize(R.dimen.all_apps_header_pill_height)
: 0;
mViewPagerTopPadding = mHasWorkProfile
? getContext().getResources()
.getDimensionPixelSize(R.dimen.widget_picker_view_pager_top_padding)
: 0;
- mSearchAndRecommendationContainerBottomMargin = getContext().getResources()
- .getDimensionPixelSize(mHasWorkProfile
+ mSearchAndRecommendationContainerBottomMargin = resources.getDimensionPixelSize(
+ mHasWorkProfile
? R.dimen.search_and_recommended_widgets_container_small_bottom_margin
: R.dimen.search_and_recommended_widgets_container_bottom_margin);
- mWidgetCellHorizontalPadding = 2 * getResources().getDimensionPixelOffset(
+ mWidgetSheetContentHorizontalPadding = 2 * resources.getDimensionPixelSize(
R.dimen.widget_cell_horizontal_padding);
}
@@ -375,11 +377,10 @@
private boolean updateMaxSpansPerRow() {
if (getMeasuredWidth() == 0) return false;
- int previousMaxSpansPerRow = mMaxSpansPerRow;
- mMaxSpansPerRow = getMeasuredWidth()
- / (mActivityContext.getDeviceProfile().cellWidthPx + mWidgetCellHorizontalPadding);
-
- if (previousMaxSpansPerRow != mMaxSpansPerRow) {
+ int maxHorizontalSpans = computeMaxHorizontalSpans(mContent,
+ mWidgetSheetContentHorizontalPadding);
+ if (mMaxSpansPerRow != maxHorizontalSpans) {
+ mMaxSpansPerRow = maxHorizontalSpans;
mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.setMaxHorizontalSpansPerRow(
mMaxSpansPerRow);
mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.setMaxHorizontalSpansPerRow(