diff --git a/go/quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml b/go/quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml index b438da32eb..e6af84868e 100644 --- a/go/quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml +++ b/go/quickstep/overview_ui_overrides/res/layout/overview_actions_container.xml @@ -17,14 +17,14 @@ addTaskbarIfNecessary()); } diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index 7404dee9d1..64b22d439c 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -84,7 +84,6 @@ import com.android.quickstep.util.RemoteAnimationProvider; import com.android.quickstep.util.StaggeredWorkspaceAnim; import com.android.quickstep.util.SurfaceTransactionApplier; import com.android.quickstep.views.RecentsView; -import com.android.systemui.shared.recents.IStartingWindowListener; import com.android.systemui.shared.system.ActivityCompat; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; @@ -96,6 +95,7 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.RemoteTransitionCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; import com.android.systemui.shared.system.WindowManagerWrapper; +import com.android.wm.shell.startingsurface.IStartingWindowListener; import java.util.LinkedHashMap; @@ -309,9 +309,11 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener // before our internal listeners. mLauncher.getStateManager().setCurrentAnimation(anim); - Rect windowTargetBounds = getWindowTargetBounds(appTargets); + final int rotationChange = getRotationChange(appTargets); + // Note: the targetBounds are relative to the launcher + Rect windowTargetBounds = getWindowTargetBounds(appTargets, rotationChange); anim.play(getOpeningWindowAnimators(v, appTargets, wallpaperTargets, windowTargetBounds, - areAllTargetsTranslucent(appTargets))); + areAllTargetsTranslucent(appTargets), rotationChange)); if (launcherClosing) { Pair launcherContentAnimator = getLauncherContentAnimator(true /* isAppOpening */, @@ -340,19 +342,29 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener * In multiwindow mode, we need to get the final size of the opening app window target to help * figure out where the floating view should animate to. */ - private Rect getWindowTargetBounds(RemoteAnimationTargetCompat[] appTargets) { - Rect bounds = new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx); - if (mLauncher.isInMultiWindowMode()) { - for (RemoteAnimationTargetCompat target : appTargets) { - if (target.mode == MODE_OPENING) { - bounds.set(target.screenSpaceBounds); - if (target.localBounds != null) { - bounds.set(target.localBounds); - } else { - bounds.offsetTo(target.position.x, target.position.y); - } - return bounds; - } + private Rect getWindowTargetBounds(@NonNull RemoteAnimationTargetCompat[] appTargets, + int rotationChange) { + RemoteAnimationTargetCompat target = null; + for (RemoteAnimationTargetCompat t : appTargets) { + if (t.mode != MODE_OPENING) continue; + target = t; + break; + } + if (target == null) return new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx); + final Rect bounds = new Rect(target.screenSpaceBounds); + if (target.localBounds != null) { + bounds.set(target.localBounds); + } else { + bounds.offsetTo(target.position.x, target.position.y); + } + if (rotationChange != 0) { + if ((rotationChange % 2) == 1) { + // undoing rotation, so our "original" parent size is actually flipped + Utilities.rotateBounds(bounds, mDeviceProfile.heightPx, mDeviceProfile.widthPx, + 4 - rotationChange); + } else { + Utilities.rotateBounds(bounds, mDeviceProfile.widthPx, mDeviceProfile.heightPx, + 4 - rotationChange); } } return bounds; @@ -502,7 +514,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener private Animator getOpeningWindowAnimators(View v, RemoteAnimationTargetCompat[] appTargets, RemoteAnimationTargetCompat[] wallpaperTargets, - Rect windowTargetBounds, boolean appTargetsAreTranslucent) { + Rect windowTargetBounds, boolean appTargetsAreTranslucent, int rotationChange) { RectF launcherIconBounds = new RectF(); FloatingIconView floatingView = FloatingIconView.getFloatingIconView(mLauncher, v, !appTargetsAreTranslucent, launcherIconBounds, true /* isOpening */); @@ -602,6 +614,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener final int windowCropWidth = crop.width(); final int windowCropHeight = crop.height(); + if (rotationChange != 0) { + Utilities.rotateBounds(crop, mDeviceProfile.widthPx, + mDeviceProfile.heightPx, rotationChange); + } // Scale the size of the icon to match the size of the window crop. float scaleX = iconWidth / windowCropWidth; @@ -641,7 +657,20 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener if (target.mode == MODE_OPENING) { matrix.setScale(scale, scale); - matrix.postTranslate(windowTransX0, windowTransY0); + if (rotationChange == 1) { + matrix.postTranslate(windowTransY0, + mDeviceProfile.widthPx - (windowTransX0 + scaledCropWidth)); + } else if (rotationChange == 2) { + matrix.postTranslate( + mDeviceProfile.widthPx - (windowTransX0 + scaledCropWidth), + mDeviceProfile.heightPx - (windowTransY0 + scaledCropHeight)); + } else if (rotationChange == 3) { + matrix.postTranslate( + mDeviceProfile.heightPx - (windowTransY0 + scaledCropHeight), + windowTransX0); + } else { + matrix.postTranslate(windowTransX0, windowTransY0); + } floatingView.update(floatingIconBounds, mIconAlpha.value, percent, 0f, mWindowRadius.value * scale, true /* isOpening */); @@ -650,17 +679,25 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener .withAlpha(1f - mIconAlpha.value) .withCornerRadius(mWindowRadius.value) .withShadowRadius(mShadowRadius.value); - } else { + } else if (target.mode == MODE_CLOSING) { if (target.localBounds != null) { final Rect localBounds = target.localBounds; tmpPos.set(target.localBounds.left, target.localBounds.top); } else { tmpPos.set(target.position.x, target.position.y); } - - matrix.setTranslate(tmpPos.x, tmpPos.y); final Rect crop = new Rect(target.screenSpaceBounds); crop.offsetTo(0, 0); + + if ((rotationChange % 2) == 1) { + int tmp = crop.right; + crop.right = crop.bottom; + crop.bottom = tmp; + tmp = tmpPos.x; + tmpPos.x = tmpPos.y; + tmpPos.y = tmp; + } + matrix.setTranslate(tmpPos.x, tmpPos.y); builder.withMatrix(matrix) .withWindowCrop(crop) .withAlpha(1f); @@ -817,14 +854,26 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener return unlockAnimator; } + private static int getRotationChange(RemoteAnimationTargetCompat[] appTargets) { + int rotationChange = 0; + for (RemoteAnimationTargetCompat target : appTargets) { + if (Math.abs(target.rotationChange) > Math.abs(rotationChange)) { + rotationChange = target.rotationChange; + } + } + return rotationChange; + } + /** * Animator that controls the transformations of the windows the targets that are closing. */ private Animator getClosingWindowAnimators(RemoteAnimationTargetCompat[] appTargets, RemoteAnimationTargetCompat[] wallpaperTargets) { + final int rotationChange = getRotationChange(appTargets); SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(mDragLayer); Matrix matrix = new Matrix(); Point tmpPos = new Point(); + Rect tmpRect = new Rect(); ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1); int duration = CLOSING_TRANSITION_DURATION_MS; float windowCornerRadius = mDeviceProfile.isMultiWindowMode @@ -851,26 +900,32 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener tmpPos.set(target.position.x, target.position.y); } + final Rect crop = new Rect(target.screenSpaceBounds); + crop.offsetTo(0, 0); if (target.mode == MODE_CLOSING) { + tmpRect.set(target.screenSpaceBounds); + if ((rotationChange % 2) != 0) { + final int right = crop.right; + crop.right = crop.bottom; + crop.bottom = right; + } matrix.setScale(mScale.value, mScale.value, - target.screenSpaceBounds.centerX(), - target.screenSpaceBounds.centerY()); + tmpRect.centerX(), + tmpRect.centerY()); matrix.postTranslate(0, mDy.value); matrix.postTranslate(tmpPos.x, tmpPos.y); builder.withMatrix(matrix) + .withWindowCrop(crop) .withAlpha(mAlpha.value) .withCornerRadius(windowCornerRadius) .withShadowRadius(mShadowRadius.value); - } else { + } else if (target.mode == MODE_OPENING) { matrix.setTranslate(tmpPos.x, tmpPos.y); builder.withMatrix(matrix) + .withWindowCrop(crop) .withAlpha(1f); } - final Rect crop = new Rect(target.screenSpaceBounds); - crop.offsetTo(0, 0); - params[i] = builder - .withWindowCrop(crop) - .build(); + params[i] = builder.build(); } surfaceApplier.scheduleApply(params); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java index a2b2ddd5dd..f652961629 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java @@ -472,7 +472,7 @@ public class TaskbarController { public void alignRealHotseatWithTaskbar() { Rect hotseatBounds = new Rect(); DeviceProfile grid = mLauncher.getDeviceProfile(); - int hotseatHeight = grid.workspacePadding.bottom + grid.getInsets().bottom; + int hotseatHeight = grid.workspacePadding.bottom + grid.taskbarSize; int hotseatTopDiff = hotseatHeight - grid.taskbarSize; mTaskbarView.getHotseatBoundsAtScale(getTaskbarScaleOnHome()).roundOut(hotseatBounds); diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 6da2201dc9..30945007a9 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -1334,7 +1334,11 @@ public abstract class AbsSwipeUpHandler, } private void invalidateHandler() { - mInputConsumerProxy.destroy(); + if (!LIVE_TILE.get() || !mActivityInterface.isInLiveTileMode() + || mGestureState.getEndTarget() != RECENTS) { + mInputConsumerProxy.destroy(); + mTaskAnimationManager.setLiveTileCleanUpHandler(null); + } endRunningWindowAnim(false /* cancel */); if (mGestureEndCallback != null) { @@ -1526,6 +1530,7 @@ public abstract class AbsSwipeUpHandler, apps[apps.length - 1] = appearedTaskTarget; launchOtherTaskInLiveTileMode(appearedTaskTarget.taskId, apps); }); + mTaskAnimationManager.setLiveTileCleanUpHandler(mInputConsumerProxy::destroy); ActivityManagerWrapper.getInstance().registerTaskStackListener( mLiveTileRestartListener); } diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index a70cc4ccd2..cf71eaeeb8 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -35,12 +35,17 @@ import android.util.Log; import android.view.MotionEvent; import com.android.launcher3.util.MainThreadInitializedObject; -import com.android.systemui.shared.recents.IPinnedStackAnimationListener; -import com.android.systemui.shared.recents.ISplitScreenListener; -import com.android.systemui.shared.recents.IStartingWindowListener; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.RemoteTransitionCompat; +import com.android.wm.shell.onehanded.IOneHanded; +import com.android.wm.shell.pip.IPip; +import com.android.wm.shell.pip.IPipAnimationListener; +import com.android.wm.shell.splitscreen.ISplitScreen; +import com.android.wm.shell.splitscreen.ISplitScreenListener; +import com.android.wm.shell.startingsurface.IStartingWindow; +import com.android.wm.shell.startingsurface.IStartingWindowListener; +import com.android.wm.shell.transition.IShellTransitions; /** * Holds the reference to SystemUI. @@ -53,8 +58,13 @@ public class SystemUiProxy implements ISystemUiProxy, new MainThreadInitializedObject<>(SystemUiProxy::new); private ISystemUiProxy mSystemUiProxy; + private IPip mPip; + private ISplitScreen mSplitScreen; + private IOneHanded mOneHanded; + private IShellTransitions mShellTransitions; + private IStartingWindow mStartingWindow; private final DeathRecipient mSystemUiProxyDeathRecipient = () -> { - MAIN_EXECUTOR.execute(() -> setProxy(null)); + MAIN_EXECUTOR.execute(() -> clearProxy()); }; // Used to dedupe calls to SystemUI @@ -83,12 +93,23 @@ public class SystemUiProxy implements ISystemUiProxy, return null; } - public void setProxy(ISystemUiProxy proxy) { + public void setProxy(ISystemUiProxy proxy, IPip pip, ISplitScreen splitScreen, + IOneHanded oneHanded, IShellTransitions shellTransitions, + IStartingWindow startingWindow) { unlinkToDeath(); mSystemUiProxy = proxy; + mPip = pip; + mSplitScreen = splitScreen; + mOneHanded = oneHanded; + mShellTransitions = shellTransitions; + mStartingWindow = startingWindow; linkToDeath(); } + public void clearProxy() { + setProxy(null, null, null, null, null, null); + } + // TODO(141886704): Find a way to remove this public void setLastSystemUiStateFlags(int stateFlags) { mLastSystemUiStateFlags = stateFlags; @@ -267,21 +288,6 @@ public class SystemUiProxy implements ISystemUiProxy, } } - @Override - public void setShelfHeight(boolean visible, int shelfHeight) { - boolean changed = visible != mLastShelfVisible || shelfHeight != mLastShelfHeight; - if (mSystemUiProxy != null && changed) { - mLastShelfVisible = visible; - mLastShelfHeight = shelfHeight; - try { - mSystemUiProxy.setShelfHeight(visible, shelfHeight); - } catch (RemoteException e) { - Log.w(TAG, "Failed call setShelfHeight visible: " + visible - + " height: " + shelfHeight, e); - } - } - } - @Override public void handleImageAsScreenshot(Bitmap bitmap, Rect rect, Insets insets, int i) { if (mSystemUiProxy != null) { @@ -318,20 +324,6 @@ public class SystemUiProxy implements ISystemUiProxy, } } - /** - * Sets listener to get pinned stack animation callbacks. - */ - @Override - public void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) { - if (mSystemUiProxy != null) { - try { - mSystemUiProxy.setPinnedStackAnimationListener(listener); - } catch (RemoteException e) { - Log.w(TAG, "Failed call setPinnedStackAnimationListener", e); - } - } - } - @Override public void onQuickSwitchToNewTask(int rotation) { if (mSystemUiProxy != null) { @@ -356,28 +348,6 @@ public class SystemUiProxy implements ISystemUiProxy, } } - @Override - public void startOneHandedMode() { - if (mSystemUiProxy != null) { - try { - mSystemUiProxy.startOneHandedMode(); - } catch (RemoteException e) { - Log.w(TAG, "Failed call startOneHandedMode", e); - } - } - } - - @Override - public void stopOneHandedMode() { - if (mSystemUiProxy != null) { - try { - mSystemUiProxy.stopOneHandedMode(); - } catch (RemoteException e) { - Log.w(TAG, "Failed call stopOneHandedMode", e); - } - } - } - @Override public void expandNotificationPanel() { if (mSystemUiProxy != null) { @@ -389,12 +359,45 @@ public class SystemUiProxy implements ISystemUiProxy, } } - @Override + // + // Pip + // + + /** + * Sets the shelf height. + */ + public void setShelfHeight(boolean visible, int shelfHeight) { + boolean changed = visible != mLastShelfVisible || shelfHeight != mLastShelfHeight; + if (mPip != null && changed) { + mLastShelfVisible = visible; + mLastShelfHeight = shelfHeight; + try { + mPip.setShelfHeight(visible, shelfHeight); + } catch (RemoteException e) { + Log.w(TAG, "Failed call setShelfHeight visible: " + visible + + " height: " + shelfHeight, e); + } + } + } + + /** + * Sets listener to get pinned stack animation callbacks. + */ + public void setPinnedStackAnimationListener(IPipAnimationListener listener) { + if (mPip != null) { + try { + mPip.setPinnedStackAnimationListener(listener); + } catch (RemoteException e) { + Log.w(TAG, "Failed call setPinnedStackAnimationListener", e); + } + } + } + public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo, PictureInPictureParams pictureInPictureParams, int launcherRotation, int shelfHeight) { - if (mSystemUiProxy != null) { + if (mPip != null) { try { - return mSystemUiProxy.startSwipePipToHome(componentName, activityInfo, + return mPip.startSwipePipToHome(componentName, activityInfo, pictureInPictureParams, launcherRotation, shelfHeight); } catch (RemoteException e) { Log.w(TAG, "Failed call startSwipePipToHome", e); @@ -403,111 +406,85 @@ public class SystemUiProxy implements ISystemUiProxy, return null; } - @Override public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) { - if (mSystemUiProxy != null) { + if (mPip != null) { try { - mSystemUiProxy.stopSwipePipToHome(componentName, destinationBounds); + mPip.stopSwipePipToHome(componentName, destinationBounds); } catch (RemoteException e) { Log.w(TAG, "Failed call stopSwipePipToHome"); } } } - @Override - public void registerRemoteTransition(RemoteTransitionCompat remoteTransition) { - if (mSystemUiProxy != null) { - try { - mSystemUiProxy.registerRemoteTransition(remoteTransition); - } catch (RemoteException e) { - Log.w(TAG, "Failed call registerRemoteTransition"); - } - } - } + // + // Splitscreen + // - @Override - public void unregisterRemoteTransition(RemoteTransitionCompat remoteTransition) { - if (mSystemUiProxy != null) { - try { - mSystemUiProxy.unregisterRemoteTransition(remoteTransition); - } catch (RemoteException e) { - Log.w(TAG, "Failed call registerRemoteTransition"); - } - } - } - - @Override public void registerSplitScreenListener(ISplitScreenListener listener) { - if (mSystemUiProxy != null) { + if (mSplitScreen != null) { try { - mSystemUiProxy.registerSplitScreenListener(listener); + mSplitScreen.registerSplitScreenListener(listener); } catch (RemoteException e) { Log.w(TAG, "Failed call registerSplitScreenListener"); } } } - @Override public void unregisterSplitScreenListener(ISplitScreenListener listener) { - if (mSystemUiProxy != null) { + if (mSplitScreen != null) { try { - mSystemUiProxy.unregisterSplitScreenListener(listener); + mSplitScreen.unregisterSplitScreenListener(listener); } catch (RemoteException e) { Log.w(TAG, "Failed call unregisterSplitScreenListener"); } } } - @Override public void setSideStageVisibility(boolean visible) { - if (mSystemUiProxy != null) { + if (mSplitScreen != null) { try { - mSystemUiProxy.setSideStageVisibility(visible); + mSplitScreen.setSideStageVisibility(visible); } catch (RemoteException e) { Log.w(TAG, "Failed call setSideStageVisibility"); } } } - @Override public void exitSplitScreen() { - if (mSystemUiProxy != null) { + if (mSplitScreen != null) { try { - mSystemUiProxy.exitSplitScreen(); + mSplitScreen.exitSplitScreen(); } catch (RemoteException e) { Log.w(TAG, "Failed call exitSplitScreen"); } } } - @Override public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) { - if (mSystemUiProxy != null) { + if (mSplitScreen != null) { try { - mSystemUiProxy.exitSplitScreenOnHide(exitSplitScreenOnHide); + mSplitScreen.exitSplitScreenOnHide(exitSplitScreenOnHide); } catch (RemoteException e) { Log.w(TAG, "Failed call exitSplitScreen"); } } } - @Override public void startTask(int taskId, int stage, int position, Bundle options) { - if (mSystemUiProxy != null) { + if (mSplitScreen != null) { try { - mSystemUiProxy.startTask(taskId, stage, position, options); + mSplitScreen.startTask(taskId, stage, position, options); } catch (RemoteException e) { Log.w(TAG, "Failed call startTask"); } } } - @Override public void startShortcut(String packageName, String shortcutId, int stage, int position, Bundle options, UserHandle user) { - if (mSystemUiProxy != null) { + if (mSplitScreen != null) { try { - mSystemUiProxy.startShortcut(packageName, shortcutId, stage, position, options, + mSplitScreen.startShortcut(packageName, shortcutId, stage, position, options, user); } catch (RemoteException e) { Log.w(TAG, "Failed call startShortcut"); @@ -515,38 +492,87 @@ public class SystemUiProxy implements ISystemUiProxy, } } - @Override - public void startIntent(PendingIntent intent, Intent fillInIntent, int stage, - int position, Bundle options) { - if (mSystemUiProxy != null) { + public void startIntent(PendingIntent intent, Intent fillInIntent, int stage, int position, + Bundle options) { + if (mSplitScreen != null) { try { - mSystemUiProxy.startIntent(intent, fillInIntent, stage, position, - options); + mSplitScreen.startIntent(intent, fillInIntent, stage, position, options); } catch (RemoteException e) { Log.w(TAG, "Failed call startIntent"); } } } - @Override public void removeFromSideStage(int taskId) { - if (mSystemUiProxy != null) { + if (mSplitScreen != null) { try { - mSystemUiProxy.removeFromSideStage(taskId); + mSplitScreen.removeFromSideStage(taskId); } catch (RemoteException e) { Log.w(TAG, "Failed call removeFromSideStage"); } } } + // + // One handed + // + + public void startOneHandedMode() { + if (mOneHanded != null) { + try { + mOneHanded.startOneHanded(); + } catch (RemoteException e) { + Log.w(TAG, "Failed call startOneHandedMode", e); + } + } + } + + public void stopOneHandedMode() { + if (mOneHanded != null) { + try { + mOneHanded.stopOneHanded(); + } catch (RemoteException e) { + Log.w(TAG, "Failed call stopOneHandedMode", e); + } + } + } + + // + // Remote transitions + // + + public void registerRemoteTransition(RemoteTransitionCompat remoteTransition) { + if (mShellTransitions != null) { + try { + mShellTransitions.registerRemote(remoteTransition.getFilter(), + remoteTransition.getTransition()); + } catch (RemoteException e) { + Log.w(TAG, "Failed call registerRemoteTransition"); + } + } + } + + public void unregisterRemoteTransition(RemoteTransitionCompat remoteTransition) { + if (mShellTransitions != null) { + try { + mShellTransitions.unregisterRemote(remoteTransition.getTransition()); + } catch (RemoteException e) { + Log.w(TAG, "Failed call registerRemoteTransition"); + } + } + } + + // + // Starting window + // + /** * Sets listener to get callbacks when launching a task. */ - @Override public void setStartingWindowListener(IStartingWindowListener listener) { - if (mSystemUiProxy != null) { + if (mStartingWindow != null) { try { - mSystemUiProxy.setStartingWindowListener(listener); + mStartingWindow.setStartingWindowListener(listener); } catch (RemoteException e) { Log.w(TAG, "Failed call setStartingWindowListener", e); } diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java index 02c27636fc..9a454f2bd7 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -50,6 +50,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn private GestureState mLastGestureState; private RemoteAnimationTargetCompat mLastAppearedTaskTarget; private Consumer mLaunchOtherTaskHandler; + private Runnable mLiveTileCleanUpHandler; private Context mCtx; TaskAnimationManager(Context ctx) { @@ -169,6 +170,10 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn mLaunchOtherTaskHandler = handler; } + public void setLiveTileCleanUpHandler(Runnable runnable) { + mLiveTileCleanUpHandler = runnable; + } + /** * Finishes the running recents animation. */ @@ -206,6 +211,11 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn * Cleans up the recents animation entirely. */ private void cleanUpRecentsAnimation() { + if (mLiveTileCleanUpHandler != null) { + mLiveTileCleanUpHandler.run(); + mLiveTileCleanUpHandler = null; + } + // Release all the target leashes if (mTargets != null) { mTargets.release(); diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 8e6f663bed..4747f1898d 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -25,6 +25,11 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.quickstep.GestureState.DEFAULT_STATE; import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED; @@ -102,6 +107,11 @@ import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.InputMonitorCompat; import com.android.systemui.shared.tracing.ProtoTraceable; +import com.android.wm.shell.onehanded.IOneHanded; +import com.android.wm.shell.pip.IPip; +import com.android.wm.shell.splitscreen.ISplitScreen; +import com.android.wm.shell.startingsurface.IStartingWindow; +import com.android.wm.shell.transition.IShellTransitions; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -141,8 +151,18 @@ public class TouchInteractionService extends Service implements PluginListener { - SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy); + SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip, + splitscreen, onehanded, shellTransitions, startingWindow); TouchInteractionService.this.initInputMonitor(); preloadOverview(true /* fromInit */); mDeviceState.runOnUserUnlocked(() -> { @@ -432,7 +452,7 @@ public class TouchInteractionService extends Service implements PluginListener extends PagedView } }; - private final PinnedStackAnimationListener mIPinnedStackAnimationListener = + private final PinnedStackAnimationListener mIPipAnimationListener = new PinnedStackAnimationListener(); // Used to keep track of the last requested task list id, so that we do not request to load the @@ -614,9 +615,6 @@ public abstract class RecentsView extends PagedView @Override protected void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); - if (visibility != VISIBLE && LIVE_TILE.get()) { - finishRecentsAnimation(true /* toRecents */, null); - } updateTaskStackListenerState(); } @@ -656,9 +654,9 @@ public abstract class RecentsView extends PagedView mLiveTileParams.setSyncTransactionApplier(mSyncTransactionApplier); RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this); mIdp.addOnChangeListener(this); - mIPinnedStackAnimationListener.setActivity(mActivity); + mIPipAnimationListener.setActivity(mActivity); SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener( - mIPinnedStackAnimationListener); + mIPipAnimationListener); mOrientationState.initListeners(); SplitScreenBounds.INSTANCE.addOnChangeListener(this); mTaskOverlayFactory.initListeners(); @@ -677,7 +675,7 @@ public abstract class RecentsView extends PagedView mIdp.removeOnChangeListener(this); SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(null); SplitScreenBounds.INSTANCE.removeOnChangeListener(this); - mIPinnedStackAnimationListener.setActivity(null); + mIPipAnimationListener.setActivity(null); mOrientationState.destroyListeners(); mTaskOverlayFactory.removeListeners(); } @@ -3136,7 +3134,7 @@ public abstract class RecentsView extends PagedView } private static class PinnedStackAnimationListener extends - IPinnedStackAnimationListener.Stub { + IPipAnimationListener.Stub { private T mActivity; public void setActivity(T activity) { @@ -3144,10 +3142,12 @@ public abstract class RecentsView extends PagedView } @Override - public void onPinnedStackAnimationStarted() { - // Needed for activities that auto-enter PiP, which will not trigger a remote - // animation to be created - mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS); + public void onPipAnimationStarted() { + MAIN_EXECUTOR.execute(() -> { + // Needed for activities that auto-enter PiP, which will not trigger a remote + // animation to be created + mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS); + }); } } } diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java index 17d075f6c8..2b54f95bdf 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java @@ -550,23 +550,26 @@ public class TaskThumbnailView extends View implements PluginListener - + \ No newline at end of file diff --git a/res/drawable/middle_item_primary.xml b/res/drawable/middle_item_primary.xml new file mode 100644 index 0000000000..c9757142da --- /dev/null +++ b/res/drawable/middle_item_primary.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable/single_item_primary.xml b/res/drawable/single_item_primary.xml new file mode 100644 index 0000000000..1c0889bd23 --- /dev/null +++ b/res/drawable/single_item_primary.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable/single_item_secondary.xml b/res/drawable/single_item_secondary.xml new file mode 100644 index 0000000000..4edc4813aa --- /dev/null +++ b/res/drawable/single_item_secondary.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/res/layout/deep_shortcut.xml b/res/layout/deep_shortcut.xml index 840a8b776d..d6b4a37dd4 100644 --- a/res/layout/deep_shortcut.xml +++ b/res/layout/deep_shortcut.xml @@ -19,6 +19,7 @@ xmlns:launcher="http://schemas.android.com/apk/res-auto" android:layout_width="@dimen/bg_popup_item_width" android:layout_height="@dimen/bg_popup_item_height" + android:background="@drawable/middle_item_primary" android:theme="@style/PopupItem" > - - diff --git a/res/layout/longpress_options_menu.xml b/res/layout/longpress_options_menu.xml index 20bb5b81be..3898365b1c 100644 --- a/res/layout/longpress_options_menu.xml +++ b/res/layout/longpress_options_menu.xml @@ -18,7 +18,6 @@ android:id="@+id/deep_shortcuts_container" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:background="?attr/popupColorPrimary" android:clipToPadding="false" android:clipChildren="false" android:elevation="@dimen/deep_shortcuts_elevation" diff --git a/res/layout/notification_content.xml b/res/layout/notification_content.xml index d01be019eb..147aa30525 100644 --- a/res/layout/notification_content.xml +++ b/res/layout/notification_content.xml @@ -96,14 +96,6 @@ - - - \ No newline at end of file + android:layout_height="0dp" + android:layout_marginTop="@dimen/popup_margin" /> \ No newline at end of file diff --git a/res/layout/popup_container.xml b/res/layout/popup_container.xml index c73740771d..04822fd7a2 100644 --- a/res/layout/popup_container.xml +++ b/res/layout/popup_container.xml @@ -19,8 +19,15 @@ android:id="@+id/deep_shortcuts_container" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:background="?attr/popupColorPrimary" android:clipToPadding="false" android:clipChildren="false" android:elevation="@dimen/deep_shortcuts_elevation" - android:orientation="vertical" /> \ No newline at end of file + android:orientation="vertical"> + + \ No newline at end of file diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml index c620e2af57..68251e4d15 100644 --- a/res/layout/system_shortcut.xml +++ b/res/layout/system_shortcut.xml @@ -19,6 +19,7 @@ xmlns:launcher="http://schemas.android.com/apk/res-auto" android:layout_width="@dimen/bg_popup_item_width" android:layout_height="@dimen/bg_popup_item_height" + android:background="@drawable/middle_item_primary" android:theme="@style/PopupItem" > - - diff --git a/res/layout/system_shortcut_icons.xml b/res/layout/system_shortcut_icons.xml index a340f4fc9d..f9922488fb 100644 --- a/res/layout/system_shortcut_icons.xml +++ b/res/layout/system_shortcut_icons.xml @@ -21,7 +21,7 @@ android:layout_height="@dimen/system_shortcut_header_height" android:orientation="horizontal" android:gravity="end|center_vertical" - android:background="?attr/popupColorSecondary" + android:background="@drawable/single_item_secondary" android:clipToPadding="true"> diff --git a/res/layout/widgets_full_sheet_paged_view.xml b/res/layout/widgets_full_sheet_paged_view.xml index 8125db8333..ae877d46bf 100644 --- a/res/layout/widgets_full_sheet_paged_view.xml +++ b/res/layout/widgets_full_sheet_paged_view.xml @@ -16,11 +16,6 @@ - - + \ No newline at end of file diff --git a/res/layout/widgets_list_row_header.xml b/res/layout/widgets_list_row_header.xml index 62345b39a6..ed3a042148 100644 --- a/res/layout/widgets_list_row_header.xml +++ b/res/layout/widgets_list_row_header.xml @@ -71,6 +71,7 @@ android:layout_gravity="center_vertical" android:layout_alignParentEnd="true" android:clickable="false" + android:importantForAccessibility="no" android:button="@drawable/widgets_tray_expand_button"/> \ No newline at end of file diff --git a/res/layout/widgets_search_bar.xml b/res/layout/widgets_search_bar.xml index cf693bbd1d..021058b65d 100644 --- a/res/layout/widgets_search_bar.xml +++ b/res/layout/widgets_search_bar.xml @@ -19,12 +19,15 @@ android:hint="@string/widgets_full_sheet_search_bar_hint" android:maxLines="1" android:layout_weight="1" - android:inputType="text"/> + android:inputType="text" + android:textColor="?android:attr/textColorSecondary" + android:textColorHint="?android:attr/textColorTertiary"/> 2dp - 9dp - + 0dp 234dp 56dp 48dp 6dp 16dp - 36dp - 8dp + 32dp + 2dp + 100dp + 4dp + 12dp 16dp 10dp 16dp @@ -201,16 +203,14 @@ 10dp -1dp - 28dp + 26dp 2dp - 56dp - - 178dp + 52dp 24dp - + 16dp - 48dp + 56dp 48dp 12dp diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index cc4bfe8c74..9df8d44d58 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -181,8 +181,6 @@ public class CellLayout extends ViewGroup { private final ArrayList mIntersectingViews = new ArrayList<>(); private final Rect mOccupiedRect = new Rect(); private final int[] mDirectionVector = new int[2]; - private final Workspace mWorkspace; - private final DeviceProfile mDeviceProfile; final int[] mPreviousReorderDirection = new int[2]; private static final int INVALID_DIRECTION = -100; @@ -213,15 +211,14 @@ public class CellLayout extends ViewGroup { setWillNotDraw(false); setClipToPadding(false); mActivity = ActivityContext.lookupContext(context); - mWorkspace = Launcher.cast(mActivity).getWorkspace(); - mDeviceProfile = mActivity.getDeviceProfile(); + DeviceProfile deviceProfile = mActivity.getDeviceProfile(); - mBorderSpacing = mDeviceProfile.cellLayoutBorderSpacingPx; + mBorderSpacing = deviceProfile.cellLayoutBorderSpacingPx; mCellWidth = mCellHeight = -1; mFixedCellWidth = mFixedCellHeight = -1; - mCountX = mDeviceProfile.inv.numColumns; - mCountY = mDeviceProfile.inv.numRows; + mCountX = deviceProfile.inv.numColumns; + mCountY = deviceProfile.inv.numRows; mOccupied = new GridOccupancy(mCountX, mCountY); mTmpOccupied = new GridOccupancy(mCountX, mCountY); @@ -238,7 +235,7 @@ public class CellLayout extends ViewGroup { mBackground.setCallback(this); mBackground.setAlpha(0); - mReorderPreviewAnimationMagnitude = (REORDER_PREVIEW_MAGNITUDE * mDeviceProfile.iconSizePx); + mReorderPreviewAnimationMagnitude = (REORDER_PREVIEW_MAGNITUDE * deviceProfile.iconSizePx); // Initialize the data structures used for the drag visualization. mEaseOutInterpolator = Interpolators.DEACCEL_2_5; // Quint ease out @@ -1024,8 +1021,10 @@ public class CellLayout extends ViewGroup { // Apply local extracted color if the DragView is an AppWidgetHostViewDrawable. Drawable drawable = dragObject.dragView.getDrawable(); if (drawable instanceof AppWidgetHostViewDrawable) { - int screenId = mWorkspace.getIdForScreen(this); - int pageId = mWorkspace.getPageIndexForScreenId(screenId); + Workspace workspace = + Launcher.getLauncher(dragObject.dragView.getContext()).getWorkspace(); + int screenId = workspace.getIdForScreen(this); + int pageId = workspace.getPageIndexForScreenId(screenId); AppWidgetHostViewDrawable hostViewDrawable = ((AppWidgetHostViewDrawable) drawable); cellToRect(targetCell[0], targetCell[1], spanX, spanY, mTempRect); hostViewDrawable.getAppWidgetHostView().handleDrag(mTempRect, pageId); @@ -2097,7 +2096,7 @@ public class CellLayout extends ViewGroup { private void commitTempPlacement() { mTmpOccupied.copyTo(mOccupied); - int screenId = mWorkspace.getIdForScreen(this); + int screenId = Launcher.cast(mActivity).getWorkspace().getIdForScreen(this); int container = Favorites.CONTAINER_DESKTOP; if (mContainerType == HOTSEAT) { diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 0e9de45e2f..af4a843b12 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -29,7 +29,6 @@ import android.widget.FrameLayout; import androidx.annotation.Nullable; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.MultiValueAlpha; import java.util.function.Consumer; @@ -96,7 +95,7 @@ public class Hotseat extends CellLayout implements Insettable { if (hasVerticalHotseat) { setGridSize(1, idp.numHotseatIcons); } else { - setGridSize(idp.numHotseatIcons, FeatureFlags.ENABLE_DEVICE_SEARCH.get() ? 2 : 1); + setGridSize(idp.numHotseatIcons, 1); } showInlineQsb(); } @@ -123,18 +122,14 @@ public class Hotseat extends CellLayout implements Insettable { lp.height = (grid.isTaskbarPresent ? grid.workspacePadding.bottom : grid.hotseatBarSizePx) - + insets.bottom; + + (grid.isTaskbarPresent ? grid.taskbarSize : insets.bottom); } if (!grid.isTaskbarPresent) { // When taskbar is present, we set the padding separately to ensure a seamless visual // handoff between taskbar and hotseat during drag and drop. Rect padding = grid.getHotseatLayoutPadding(); - int paddingBottom = padding.bottom; - if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && !grid.isVerticalBarLayout()) { - paddingBottom -= grid.hotseatBarBottomPaddingPx; - } - setPadding(padding.left, padding.top, padding.right, paddingBottom); + setPadding(padding.left, padding.top, padding.right, padding.bottom); } setLayoutParams(lp); @@ -214,7 +209,7 @@ public class Hotseat extends CellLayout implements Insettable { : dp.hotseatBarSizePx - dp.hotseatCellHeightPx - mQsbHeight; int bottom = b - t - (int) (freeSpace * QSB_CENTER_FACTOR) - - dp.getInsets().bottom; + - (dp.isTaskbarPresent ? dp.taskbarSize : dp.getInsets().bottom); int top = bottom - mQsbHeight; mQsb.layout(left, top, right, bottom); } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 94c6574c60..e57844d7df 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -700,6 +700,37 @@ public final class Utilities { return (Math.abs(first - second) / Math.abs((first + second) / 2.0f)) > bound; } + /** + * Rotates `inOutBounds` by `delta` 90-degree increments. Rotation is visually CCW. Parent + * sizes represent the "space" that will rotate carrying inOutBounds along with it to determine + * the final bounds. + */ + public static void rotateBounds(Rect inOutBounds, int parentWidth, int parentHeight, + int delta) { + int rdelta = ((delta % 4) + 4) % 4; + int origLeft = inOutBounds.left; + switch (rdelta) { + case 0: + return; + case 1: + inOutBounds.left = inOutBounds.top; + inOutBounds.top = parentWidth - inOutBounds.right; + inOutBounds.right = inOutBounds.bottom; + inOutBounds.bottom = parentWidth - origLeft; + return; + case 2: + inOutBounds.left = parentWidth - inOutBounds.right; + inOutBounds.right = parentWidth - origLeft; + return; + case 3: + inOutBounds.left = parentHeight - inOutBounds.bottom; + inOutBounds.bottom = inOutBounds.right; + inOutBounds.right = parentHeight - inOutBounds.top; + inOutBounds.top = origLeft; + return; + } + } + private static class FixedSizeEmptyDrawable extends ColorDrawable { private final int mSize; diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index c84724ff90..6a16da9cf9 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1455,7 +1455,7 @@ public class Workspace extends PagedView // TAPL can work only if UIDevice is set up as setCompressedLayoutHeirarchy(false). // Hiding workspace from the tests when it's // IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS. - return null; + return AccessibilityNodeInfo.obtain(); } return super.createAccessibilityNodeInfo(); } diff --git a/src/com/android/launcher3/allapps/search/SearchWidgetInfoContainer.java b/src/com/android/launcher3/allapps/search/SearchWidgetInfoContainer.java deleted file mode 100644 index 8e5f8cb9c0..0000000000 --- a/src/com/android/launcher3/allapps/search/SearchWidgetInfoContainer.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - */ -package com.android.launcher3.allapps.search; - -import android.appwidget.AppWidgetHostView; -import android.appwidget.AppWidgetProviderInfo; -import android.content.Context; -import android.widget.RemoteViews; - -import java.util.ArrayList; -import java.util.List; - -/** - * A placeholder {@link AppWidgetHostView} used for managing widget search results - */ -public class SearchWidgetInfoContainer extends AppWidgetHostView { - private int mAppWidgetId; - private AppWidgetProviderInfo mProviderInfo; - private RemoteViews mViews; - private List mListeners = new ArrayList<>(); - - public SearchWidgetInfoContainer(Context context) { - super(context); - } - - @Override - public void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) { - mAppWidgetId = appWidgetId; - mProviderInfo = info; - for (AppWidgetHostView listener : mListeners) { - listener.setAppWidget(mAppWidgetId, mProviderInfo); - } - } - - @Override - public void updateAppWidget(RemoteViews remoteViews) { - mViews = remoteViews; - for (AppWidgetHostView listener : mListeners) { - listener.updateAppWidget(remoteViews); - } - } - - /** - * Create a live {@link AppWidgetHostView} from placeholder - */ - public void attachWidget(AppWidgetHostView hv) { - hv.setTag(getTag()); - hv.setAppWidget(mAppWidgetId, mProviderInfo); - hv.updateAppWidget(mViews); - mListeners.add(hv); - } - - /** - * stops AppWidgetHostView from getting updates - */ - public void detachWidget(AppWidgetHostView hostView) { - mListeners.remove(hostView); - } - -} diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java index 0320aa3edd..d44d158010 100644 --- a/src/com/android/launcher3/notification/NotificationItemView.java +++ b/src/com/android/launcher3/notification/NotificationItemView.java @@ -21,10 +21,13 @@ import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL; import android.app.Notification; import android.content.Context; import android.graphics.Color; +import android.graphics.Outline; import android.graphics.Rect; import android.view.MotionEvent; import android.view.View; +import android.view.ViewGroup; import android.view.ViewGroup.MarginLayoutParams; +import android.view.ViewOutlineProvider; import android.widget.TextView; import com.android.launcher3.R; @@ -43,7 +46,8 @@ public class NotificationItemView { private static final Rect sTempRect = new Rect(); private final Context mContext; - private final PopupContainerWithArrow mContainer; + private final PopupContainerWithArrow mPopupContainer; + private final ViewGroup mRootView; private final TextView mHeaderText; private final TextView mHeaderCount; @@ -53,7 +57,6 @@ public class NotificationItemView { private final View mIconView; private final View mHeader; - private final View mDivider; private View mGutter; @@ -61,8 +64,9 @@ public class NotificationItemView { private boolean mAnimatingNextIcon; private int mNotificationHeaderTextColor = Notification.COLOR_DEFAULT; - public NotificationItemView(PopupContainerWithArrow container) { - mContainer = container; + public NotificationItemView(PopupContainerWithArrow container, ViewGroup rootView) { + mPopupContainer = container; + mRootView = rootView; mContext = container.getContext(); mHeaderText = container.findViewById(R.id.notification_text); @@ -72,17 +76,25 @@ public class NotificationItemView { mIconView = container.findViewById(R.id.popup_item_icon); mHeader = container.findViewById(R.id.header); - mDivider = container.findViewById(R.id.divider); mSwipeDetector = new SingleAxisSwipeDetector(mContext, mMainView, HORIZONTAL); mSwipeDetector.setDetectableScrollConditions(SingleAxisSwipeDetector.DIRECTION_BOTH, false); mMainView.setSwipeDetector(mSwipeDetector); mFooter.setContainer(this); + + float radius = Themes.getDialogCornerRadius(mContext); + rootView.setClipToOutline(true); + rootView.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), radius); + } + }); } public void addGutter() { if (mGutter == null) { - mGutter = mContainer.inflateAndAdd(R.layout.notification_gutter, mContainer); + mGutter = mPopupContainer.inflateAndAdd(R.layout.notification_gutter, mRootView); } } @@ -94,9 +106,8 @@ public class NotificationItemView { } public void removeFooter() { - if (mContainer.indexOfChild(mFooter) >= 0) { - mContainer.removeView(mFooter); - mContainer.removeView(mDivider); + if (mRootView.indexOfChild(mFooter) >= 0) { + mRootView.removeView(mFooter); } } @@ -108,16 +119,15 @@ public class NotificationItemView { } public void removeAllViews() { - mContainer.removeView(mMainView); - mContainer.removeView(mHeader); + mRootView.removeView(mMainView); + mRootView.removeView(mHeader); - if (mContainer.indexOfChild(mFooter) >= 0) { - mContainer.removeView(mFooter); - mContainer.removeView(mDivider); + if (mRootView.indexOfChild(mFooter) >= 0) { + mRootView.removeView(mFooter); } if (mGutter != null) { - mContainer.removeView(mGutter); + mRootView.removeView(mGutter); } } @@ -136,11 +146,11 @@ public class NotificationItemView { public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { - sTempRect.set(mMainView.getLeft(), mMainView.getTop(), - mMainView.getRight(), mMainView.getBottom()); + sTempRect.set(mRootView.getLeft(), mRootView.getTop(), + mRootView.getRight(), mRootView.getBottom()); mIgnoreTouch = !sTempRect.contains((int) ev.getX(), (int) ev.getY()); if (!mIgnoreTouch) { - mContainer.getParent().requestDisallowInterceptTouchEvent(true); + mPopupContainer.getParent().requestDisallowInterceptTouchEvent(true); } } if (mIgnoreTouch) { diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java index 15915e5380..6aa98122cd 100644 --- a/src/com/android/launcher3/popup/ArrowPopup.java +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -28,6 +28,7 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Outline; import android.graphics.Rect; +import android.graphics.drawable.GradientDrawable; import android.util.AttributeSet; import android.util.Pair; import android.view.Gravity; @@ -48,6 +49,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.RevealOutlineAnimation; import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; import com.android.launcher3.dragndrop.DragLayer; +import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.util.Themes; import com.android.launcher3.views.BaseDragLayer; @@ -75,6 +77,8 @@ public abstract class ArrowPopup extends Abstrac private final int mArrowPointRadius; private final View mArrow; + private final int mMargin; + protected boolean mIsLeftAligned; protected boolean mIsAboveIcon; private int mGravity; @@ -84,6 +88,9 @@ public abstract class ArrowPopup extends Abstrac private final Rect mStartRect = new Rect(); private final Rect mEndRect = new Rect(); + private final GradientDrawable mRoundedTop; + private final GradientDrawable mRoundedBottom; + private Runnable mOnCloseCallback = () -> { }; public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) { @@ -103,6 +110,7 @@ public abstract class ArrowPopup extends Abstrac // Initialize arrow view final Resources resources = getResources(); + mMargin = resources.getDimensionPixelSize(R.dimen.popup_margin); mArrowWidth = resources.getDimensionPixelSize(R.dimen.popup_arrow_width); mArrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height); mArrow = new View(context); @@ -111,6 +119,17 @@ public abstract class ArrowPopup extends Abstrac mArrowOffsetHorizontal = resources.getDimensionPixelSize( R.dimen.popup_arrow_horizontal_center_offset) - (mArrowWidth / 2); mArrowPointRadius = resources.getDimensionPixelSize(R.dimen.popup_arrow_corner_radius); + + mRoundedTop = new GradientDrawable(); + mRoundedTop.setColor(Themes.getAttrColor(context, R.attr.popupColorPrimary)); + mRoundedTop.setCornerRadii(new float[] { mOutlineRadius, mOutlineRadius, mOutlineRadius, + mOutlineRadius, 0, 0, 0, 0}); + + mRoundedBottom = new GradientDrawable(); + mRoundedBottom.setColor(Themes.getAttrColor(context, R.attr.popupColorPrimary)); + mRoundedBottom.setCornerRadii(new float[] { 0, 0, 0, 0, mOutlineRadius, mOutlineRadius, + mOutlineRadius, mOutlineRadius}); + } public ArrowPopup(Context context, AttributeSet attrs) { @@ -153,6 +172,50 @@ public abstract class ArrowPopup extends Abstrac */ protected void onInflationComplete(boolean isReversed) { } + /** + * Set the margins and radius of backgrounds after views are properly ordered. + */ + protected void assignMarginsAndBackgrounds() { + int count = getChildCount(); + int totalVisibleShortcuts = 0; + for (int i = 0; i < count; i++) { + View view = getChildAt(i); + if (view.getVisibility() == VISIBLE && view instanceof DeepShortcutView) { + totalVisibleShortcuts++; + } + } + + int numVisibleShortcut = 0; + View lastView = null; + for (int i = 0; i < count; i++) { + View view = getChildAt(i); + boolean isShortcut = view instanceof DeepShortcutView; + if (view.getVisibility() == VISIBLE) { + if (lastView != null) { + MarginLayoutParams mlp = (MarginLayoutParams) lastView.getLayoutParams(); + mlp.bottomMargin = mMargin; + } + lastView = view; + MarginLayoutParams mlp = (MarginLayoutParams) lastView.getLayoutParams(); + mlp.bottomMargin = 0; + + if (isShortcut) { + if (totalVisibleShortcuts == 1) { + view.setBackgroundResource(R.drawable.single_item_primary); + } else if (totalVisibleShortcuts > 1) { + if (numVisibleShortcut == 0) { + view.setBackground(mRoundedTop); + } else if (numVisibleShortcut == (totalVisibleShortcuts - 1)) { + view.setBackground(mRoundedBottom); + } + numVisibleShortcut++; + } + } + } + } + measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + } + /** * Shows the popup at the desired location, optionally reversing the children. * @param viewsToFlip number of views from the top to to flip in case of reverse order @@ -164,6 +227,8 @@ public abstract class ArrowPopup extends Abstrac reverseOrder(viewsToFlip); } onInflationComplete(reverseOrder); + assignMarginsAndBackgrounds(); + orientAboutObject(); if (shouldAddArrow()) { addArrow(); } @@ -176,6 +241,8 @@ public abstract class ArrowPopup extends Abstrac protected void show() { setupForDisplay(); onInflationComplete(false); + assignMarginsAndBackgrounds(); + orientAboutObject(); if (shouldAddArrow()) { addArrow(); } @@ -203,8 +270,6 @@ public abstract class ArrowPopup extends Abstrac for (int i = 0; i < count; i++) { addView(allViews.get(i)); } - - orientAboutObject(); } private int getArrowLeft() { @@ -408,6 +473,7 @@ public abstract class ArrowPopup extends Abstrac ? getResources().getInteger(R.integer.config_popupArrowOpenCloseDuration) : 0; } + private void animateOpen() { setVisibility(View.VISIBLE); diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index a1ba74703c..4087f49f8e 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -91,6 +91,7 @@ public class PopupContainerWithArrow extends Arr private BubbleTextView mOriginalIcon; private NotificationItemView mNotificationItemView; private int mNumNotifications; + private ViewGroup mNotificationContainer; private ViewGroup mSystemShortcutContainer; @@ -222,20 +223,6 @@ public class PopupContainerWithArrow extends Arr if (isReversed && mNotificationItemView != null) { mNotificationItemView.inverseGutterMargin(); } - - // Update dividers - int count = getChildCount(); - DeepShortcutView lastView = null; - for (int i = 0; i < count; i++) { - View view = getChildAt(i); - if (view.getVisibility() == VISIBLE && view instanceof DeepShortcutView) { - if (lastView != null) { - lastView.setDividerVisibility(VISIBLE); - } - lastView = (DeepShortcutView) view; - lastView.setDividerVisibility(INVISIBLE); - } - } } @TargetApi(Build.VERSION_CODES.P) @@ -257,8 +244,12 @@ public class PopupContainerWithArrow extends Arr // Add views if (mNumNotifications > 0) { // Add notification entries - View.inflate(getContext(), R.layout.notification_content, this); - mNotificationItemView = new NotificationItemView(this); + if (mNotificationContainer == null) { + mNotificationContainer = findViewById(R.id.notification_container); + mNotificationContainer.setVisibility(VISIBLE); + } + View.inflate(getContext(), R.layout.notification_content, mNotificationContainer); + mNotificationItemView = new NotificationItemView(this, mNotificationContainer); if (mNumNotifications == 1) { mNotificationItemView.removeFooter(); } @@ -358,21 +349,6 @@ public class PopupContainerWithArrow extends Arr } } - private void updateDividers() { - int count = getChildCount(); - DeepShortcutView lastView = null; - for (int i = 0; i < count; i++) { - View view = getChildAt(i); - if (view.getVisibility() == VISIBLE && view instanceof DeepShortcutView) { - if (lastView != null) { - lastView.setDividerVisibility(VISIBLE); - } - lastView = (DeepShortcutView) view; - lastView.setDividerVisibility(INVISIBLE); - } - } - } - private void initializeSystemShortcut(int resId, ViewGroup container, SystemShortcut info) { View view = inflateAndAdd( resId, container, getInsertIndexForSystemShortcut(container, info)); @@ -592,7 +568,7 @@ public class PopupContainerWithArrow extends Arr mNotificationItemView.removeAllViews(); mNotificationItemView = null; updateHiddenShortcuts(); - updateDividers(); + assignMarginsAndBackgrounds(); } else { mNotificationItemView.trimNotifications( NotificationKeyData.extractKeysOnly(dotInfo.getNotificationKeys())); diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutView.java b/src/com/android/launcher3/shortcuts/DeepShortcutView.java index e9b92e2f10..1c1418c325 100644 --- a/src/com/android/launcher3/shortcuts/DeepShortcutView.java +++ b/src/com/android/launcher3/shortcuts/DeepShortcutView.java @@ -41,7 +41,6 @@ public class DeepShortcutView extends FrameLayout { private BubbleTextView mBubbleText; private View mIconView; - private View mDivider; private WorkspaceItemInfo mInfo; private ShortcutInfo mDetail; @@ -63,11 +62,6 @@ public class DeepShortcutView extends FrameLayout { super.onFinishInflate(); mBubbleText = findViewById(R.id.bubble_text); mIconView = findViewById(R.id.icon); - mDivider = findViewById(R.id.divider); - } - - public void setDividerVisibility(int visibility) { - mDivider.setVisibility(visibility); } public BubbleTextView getBubbleText() { diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java index 1a114f3ce7..9a2db109ef 100644 --- a/src/com/android/launcher3/views/OptionsPopupView.java +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -134,7 +134,6 @@ public class OptionsPopupView extends ArrowPopup (DeepShortcutView) popup.inflateAndAdd(R.layout.system_shortcut, popup); view.getIconView().setBackgroundResource(item.iconRes); view.getBubbleText().setText(item.labelRes); - view.setDividerVisibility(View.INVISIBLE); view.setOnClickListener(popup); view.setOnLongClickListener(popup); popup.mItemMap.put(view, item); diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java index 8df70fbf3a..5c18faf213 100644 --- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java @@ -19,6 +19,7 @@ package com.android.launcher3.widget; import android.appwidget.AppWidgetProviderInfo; import android.content.Context; import android.content.res.Configuration; +import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.RectF; import android.os.Handler; @@ -120,8 +121,12 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView } else { super.setColorResources(colors); } + } - if (mDragListener != null) { + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (mIsInDragMode && mDragListener != null) { mDragListener.onDragContentChanged(); } } diff --git a/src/com/android/launcher3/widget/dragndrop/AppWidgetHostViewDragListener.java b/src/com/android/launcher3/widget/dragndrop/AppWidgetHostViewDragListener.java index c5e6fbd827..66bb363dde 100644 --- a/src/com/android/launcher3/widget/dragndrop/AppWidgetHostViewDragListener.java +++ b/src/com/android/launcher3/widget/dragndrop/AppWidgetHostViewDragListener.java @@ -54,6 +54,8 @@ public final class AppWidgetHostViewDragListener implements DragController.DragL /** Notifies when there is a content change in the drag view. */ public void onDragContentChanged() { - mDragObject.dragView.invalidate(); + if (mDragObject.dragView != null) { + mDragObject.dragView.invalidate(); + } } } diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java index 5747690ba6..dc375ca414 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java +++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java @@ -23,6 +23,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.PropertyValuesHolder; import android.content.Context; import android.content.pm.LauncherApps; +import android.content.res.Configuration; import android.graphics.Rect; import android.os.Process; import android.os.UserHandle; @@ -232,6 +233,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet mInsets.set(insets); setBottomPadding(mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView, insets.bottom); + setBottomPadding(mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView, insets.bottom); if (mHasWorkProfile) { setBottomPadding(mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView, insets.bottom); } @@ -276,6 +278,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet int maxSpansPerRow = getMeasuredWidth() / (deviceProfile.cellWidthPx + paddingPx); mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.setMaxHorizontalSpansPerRow( maxSpansPerRow); + mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.setMaxHorizontalSpansPerRow( + maxSpansPerRow); if (mHasWorkProfile) { mAdapters.get(AdapterHolder.WORK).mWidgetsListAdapter.setMaxHorizontalSpansPerRow( maxSpansPerRow); @@ -471,6 +475,23 @@ public class WidgetsFullSheet extends BaseWidgetSheet + marginLayoutParams.topMargin; } + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (mIsInSearchMode) { + mSearchAndRecommendationViewHolder.mSearchBar.reset(); + } + } + + @Override + public boolean onBackPressed() { + if (mIsInSearchMode) { + mSearchAndRecommendationViewHolder.mSearchBar.reset(); + return true; + } + return super.onBackPressed(); + } + /** A holder class for holding adapters & their corresponding recycler view. */ private final class AdapterHolder { static final int PRIMARY = 0; diff --git a/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java b/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java index 5520826ab9..cc336196ae 100644 --- a/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java +++ b/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java @@ -62,6 +62,11 @@ public class LauncherWidgetsSearchBar extends LinearLayout implements WidgetsSea algo, mEditText, mCancelButton, searchModeListener); } + @Override + public void reset() { + mController.clearSearchResult(); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java index af6dc48aae..ef7bf23226 100644 --- a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java +++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java @@ -29,6 +29,11 @@ public interface WidgetsSearchBar { */ void initialize(List allWidgets, SearchModeListener searchModeListener); + /** + * Clears search bar. + */ + void reset(); + /** * Sets the vertical location, in pixels, of this search bar relative to its top position. */ diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java index 3ea47660b0..f82f2cc47a 100644 --- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java +++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java @@ -132,7 +132,7 @@ public class WidgetsModel { widgetsAndShortcuts.add(new WidgetItem(info, app.getIconCache(), pm)); updatedItems.add(info); } - setWidgetsAndShortcuts(widgetsAndShortcuts, app); + setWidgetsAndShortcuts(widgetsAndShortcuts, app, packageUser); } catch (Exception e) { if (!FeatureFlags.IS_STUDIO_BUILD && Utilities.isBinderSizeError(e)) { // the returned value may be incomplete and will not be refreshed until the next @@ -149,7 +149,7 @@ public class WidgetsModel { } private synchronized void setWidgetsAndShortcuts(ArrayList rawWidgetsShortcuts, - LauncherAppState app) { + LauncherAppState app, @Nullable PackageUserKey packageUser) { if (DEBUG) { Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size()); } @@ -158,8 +158,12 @@ public class WidgetsModel { // {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList} HashMap tmpPackageItemInfos = new HashMap<>(); - // clear the lists. - mWidgetsList.clear(); + // Clear the lists only if this is an update on all widgets and shortcuts. If packageUser + // isn't null, only updates the shortcuts and widgets for the app represented in + // packageUser. + if (packageUser == null) { + mWidgetsList.clear(); + } // add and update. mWidgetsList.putAll(rawWidgetsShortcuts.stream() .filter(new WidgetValidityCheck(app))