From bb6f6e5dae072223f8505ee9791d3eec7bc72d64 Mon Sep 17 00:00:00 2001 From: Kholoud Mohamed Date: Thu, 20 May 2021 11:54:09 +0000 Subject: [PATCH 1/2] Revert "Renaming TaskbarController to LauncherTaskbarUIController" This reverts commit 40a742161938b343589e88e4b7f44b1cd67a69f1. Reason for revert: DroidMonitor-triggered revert due to breakage https://android-build.googleplex.com/builds/tests/view?invocationId=I13700009003387451&testResultId=TR89423459137251402, bug https://buganizer.corp.google.com/issues/188755902 Bug: 188755902 Change-Id: Icd1ddd43e62d392f6b68b0150a1075f73106391a --- .../launcher3/BaseQuickstepLauncher.java | 20 ++++++++-------- .../HotseatPredictionController.java | 4 ++-- .../taskbar/TaskbarAnimationController.java | 2 +- ...Controller.java => TaskbarController.java} | 9 ++++--- .../launcher3/taskbar/TaskbarManager.java | 4 ++-- .../uioverrides/QuickstepLauncher.java | 6 ++--- .../quickstep/LauncherActivityInterface.java | 24 +++++++++---------- 7 files changed, 34 insertions(+), 35 deletions(-) rename quickstep/src/com/android/launcher3/taskbar/{LauncherTaskbarUIController.java => TaskbarController.java} (97%) diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index de62e93b4e..bc2c125854 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -49,7 +49,7 @@ import com.android.launcher3.proxy.StartActivityParams; import com.android.launcher3.statehandlers.BackButtonAlphaHandler; import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.statemanager.StateManager.StateHandler; -import com.android.launcher3.taskbar.LauncherTaskbarUIController; +import com.android.launcher3.taskbar.TaskbarController; import com.android.launcher3.taskbar.TaskbarManager; import com.android.launcher3.taskbar.TaskbarStateHandler; import com.android.launcher3.uioverrides.RecentsViewStateController; @@ -96,7 +96,7 @@ public abstract class BaseQuickstepLauncher extends Launcher private OverviewActionsView mActionsView; private @Nullable TaskbarManager mTaskbarManager; - private @Nullable LauncherTaskbarUIController mTaskbarUIController; + private @Nullable TaskbarController mTaskbarController; private final ServiceConnection mTisBinderConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { @@ -261,8 +261,8 @@ public abstract class BaseQuickstepLauncher extends Launcher } - public void setTaskbarUIController(LauncherTaskbarUIController taskbarUIController) { - mTaskbarUIController = taskbarUIController; + public void setTaskbarController(TaskbarController taskbarController) { + mTaskbarController = taskbarController; } public T getActionsView() { @@ -292,8 +292,8 @@ public abstract class BaseQuickstepLauncher extends Launcher return mDepthController; } - public @Nullable LauncherTaskbarUIController getTaskbarUIController() { - return mTaskbarUIController; + public @Nullable TaskbarController getTaskbarController() { + return mTaskbarController; } public TaskbarStateHandler getTaskbarStateHandler() { @@ -349,8 +349,8 @@ public abstract class BaseQuickstepLauncher extends Launcher @Override public float getNormalTaskbarScale() { - if (mTaskbarUIController != null) { - return mTaskbarUIController.getTaskbarScaleOnHome(); + if (mTaskbarController != null) { + return mTaskbarController.getTaskbarScaleOnHome(); } return super.getNormalTaskbarScale(); } @@ -372,8 +372,8 @@ public abstract class BaseQuickstepLauncher extends Launcher } if ((changeBits & ACTIVITY_STATE_RESUMED) != 0) { - if (mTaskbarUIController != null) { - mTaskbarUIController.onLauncherResumedOrPaused(hasBeenResumed()); + if (mTaskbarController != null) { + mTaskbarController.onLauncherResumedOrPaused(hasBeenResumed()); } } diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index 85e5ab0a9b..5dcf84c249 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -263,8 +263,8 @@ public class HotseatPredictionController implements DragController.DragListener, removeOutlineDrawings(); } - if (mLauncher.getTaskbarUIController() != null) { - mLauncher.getTaskbarUIController().onHotseatUpdated(); + if (mLauncher.getTaskbarController() != null) { + mLauncher.getTaskbarController().onHotseatUpdated(); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java index e20ddf88ce..815efb9728 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java @@ -21,7 +21,7 @@ import android.animation.Animator; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.Utilities; -import com.android.launcher3.taskbar.LauncherTaskbarUIController.TaskbarAnimationControllerCallbacks; +import com.android.launcher3.taskbar.TaskbarController.TaskbarAnimationControllerCallbacks; import com.android.quickstep.AnimatedFloat; import com.android.quickstep.SystemUiProxy; import com.android.systemui.shared.system.QuickStepContract; diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java similarity index 97% rename from quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java rename to quickstep/src/com/android/launcher3/taskbar/TaskbarController.java index 67264194b2..cdae5beb9a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java @@ -38,7 +38,7 @@ import com.android.launcher3.states.StateAnimationConfig; * TODO: Rename to have Launcher prefix */ -public class LauncherTaskbarUIController extends TaskbarUIController { +public class TaskbarController extends TaskbarUIController { private final BaseQuickstepLauncher mLauncher; private final TaskbarStateHandler mTaskbarStateHandler; @@ -52,8 +52,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController { private @Nullable Animator mAnimator; private boolean mIsAnimatingToLauncher; - public LauncherTaskbarUIController( - BaseQuickstepLauncher launcher, TaskbarActivityContext context) { + public TaskbarController(BaseQuickstepLauncher launcher, TaskbarActivityContext context) { mContext = context; mTaskbarContainerView = context.getDragLayer(); mTaskbarView = mTaskbarContainerView.findViewById(R.id.taskbar_view); @@ -73,7 +72,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController { mHotseatController.init(); setTaskbarViewVisible(!mLauncher.hasBeenResumed()); alignRealHotseatWithTaskbar(); - mLauncher.setTaskbarUIController(this); + mLauncher.setTaskbarController(this); } @Override @@ -87,7 +86,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController { mHotseatController.cleanup(); setTaskbarViewVisible(true); mLauncher.getHotseat().setIconsAlpha(1f); - mLauncher.setTaskbarUIController(null); + mLauncher.setTaskbarController(null); } @Override diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index 65c87bd279..b9eec93687 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -97,7 +97,7 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen if (mTaskbarActivityContext != null) { mTaskbarActivityContext.setUIController(mLauncher == null ? TaskbarUIController.DEFAULT - : new LauncherTaskbarUIController(launcher, mTaskbarActivityContext)); + : new TaskbarController(launcher, mTaskbarActivityContext)); } } @@ -115,7 +115,7 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen mTaskbarActivityContext.init(); if (mLauncher != null) { mTaskbarActivityContext.setUIController( - new LauncherTaskbarUIController(mLauncher, mTaskbarActivityContext)); + new TaskbarController(mLauncher, mTaskbarActivityContext)); } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index f0b02b3c47..45bb521336 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -165,7 +165,7 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { @Override public boolean startActivitySafely(View v, Intent intent, ItemInfo item) { // Only pause is taskbar controller is not present - mHotseatPredictionController.setPauseUIUpdate(getTaskbarUIController() == null); + mHotseatPredictionController.setPauseUIUpdate(getTaskbarController() == null); return super.startActivitySafely(v, intent, item); } @@ -233,9 +233,9 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { @Override public void bindWorkspaceItemsChanged(List updated) { super.bindWorkspaceItemsChanged(updated); - if (getTaskbarUIController() != null && updated.stream() + if (getTaskbarController() != null && updated.stream() .filter(w -> w.container == CONTAINER_HOTSEAT).findFirst().isPresent()) { - getTaskbarUIController().onHotseatUpdated(); + getTaskbarController().onHotseatUpdated(); } } diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java index 9014774ae7..ff69180d33 100644 --- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java @@ -41,7 +41,7 @@ import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.statehandlers.DepthController.ClampedDepthProperty; import com.android.launcher3.statemanager.StateManager; -import com.android.launcher3.taskbar.LauncherTaskbarUIController; +import com.android.launcher3.taskbar.TaskbarController; import com.android.launcher3.touch.PagedOrientationHandler; import com.android.quickstep.GestureState.GestureEndTarget; import com.android.quickstep.SysUINavigationMode.Mode; @@ -163,12 +163,12 @@ public final class LauncherActivityInterface extends } @Nullable - private LauncherTaskbarUIController getTaskbarController() { + private TaskbarController getTaskbarController() { BaseQuickstepLauncher launcher = getCreatedActivity(); if (launcher == null) { return null; } - return launcher.getTaskbarUIController(); + return launcher.getTaskbarController(); } @Nullable @@ -276,13 +276,13 @@ public final class LauncherActivityInterface extends @Override public @Nullable Animator getParallelAnimationToLauncher(GestureEndTarget endTarget, long duration) { - LauncherTaskbarUIController uiController = getTaskbarController(); + TaskbarController taskbarController = getTaskbarController(); Animator superAnimator = super.getParallelAnimationToLauncher(endTarget, duration); - if (uiController == null) { + if (taskbarController == null) { return superAnimator; } LauncherState toState = stateFromGestureEndTarget(endTarget); - Animator taskbarAnimator = uiController.createAnimToLauncher(toState, duration); + Animator taskbarAnimator = taskbarController.createAnimToLauncher(toState, duration); if (superAnimator == null) { return taskbarAnimator; } else { @@ -300,20 +300,20 @@ public final class LauncherActivityInterface extends @Override public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) { - LauncherTaskbarUIController uiController = getTaskbarController(); - if (uiController == null) { + TaskbarController taskbarController = getTaskbarController(); + if (taskbarController == null) { return super.deferStartingActivity(deviceState, ev); } - return uiController.isEventOverAnyTaskbarItem(ev); + return taskbarController.isEventOverAnyTaskbarItem(ev); } @Override public boolean shouldCancelCurrentGesture() { - LauncherTaskbarUIController uiController = getTaskbarController(); - if (uiController == null) { + TaskbarController taskbarController = getTaskbarController(); + if (taskbarController == null) { return super.shouldCancelCurrentGesture(); } - return uiController.isDraggingItem(); + return taskbarController.isDraggingItem(); } @Override From 430465a3d5ff0dcdd0c2e263d862049d93075a07 Mon Sep 17 00:00:00 2001 From: Kholoud Mohamed Date: Thu, 20 May 2021 09:50:23 +0000 Subject: [PATCH 2/2] Revert "Moving taskbar lifecycle to TouchInteractionService" This reverts commit e215fb730bb3d4a357a2c4bf0c082d3c0ad69495. Reason for revert: DroidMonitor-triggered revert due to breakage https://android-build.googleplex.com/builds/tests/view?invocationId=I13700009003387451&testResultId=TR89423459137251402, bug https://buganizer.corp.google.com/issues/188755902 Bug: 188755902 Change-Id: I4650136975b60f311499ee6ff5b27ab9a32d23d6 --- quickstep/res/layout/taskbar.xml | 24 +- quickstep/res/layout/taskbar_view.xml | 26 + quickstep/res/values/dimens.xml | 1 - .../launcher3/BaseQuickstepLauncher.java | 92 +++- .../launcher3/QuickstepTransitionManager.java | 3 + .../launcher3/taskbar/ButtonProvider.java | 32 +- .../android/launcher3/taskbar/ImeBarView.java | 17 +- .../taskbar/TaskbarActivityContext.java | 230 +-------- .../taskbar/TaskbarAnimationController.java | 5 +- .../taskbar/TaskbarContainerView.java | 94 ++-- .../launcher3/taskbar/TaskbarController.java | 472 +++++++++++++++--- .../taskbar/TaskbarDragController.java | 13 +- .../taskbar/TaskbarHotseatController.java | 17 +- .../taskbar/TaskbarIconController.java | 163 ------ .../launcher3/taskbar/TaskbarManager.java | 157 ------ .../taskbar/TaskbarNavButtonController.java | 20 +- .../taskbar/TaskbarStateHandler.java | 41 +- .../taskbar/TaskbarUIController.java | 41 -- .../launcher3/taskbar/TaskbarView.java | 260 ++++++---- .../quickstep/BaseActivityInterface.java | 13 + .../quickstep/LauncherActivityInterface.java | 14 +- .../quickstep/TouchInteractionService.java | 61 ++- .../util/StaggeredWorkspaceAnim.java | 6 +- res/layout/taskbar_view.xml | 21 + src/com/android/launcher3/BubbleTextView.java | 4 + src/com/android/launcher3/Hotseat.java | 21 +- src/com/android/launcher3/Launcher.java | 14 + src/com/android/launcher3/Utilities.java | 10 +- .../launcher3/touch/ItemClickHandler.java | 56 +-- 29 files changed, 981 insertions(+), 947 deletions(-) create mode 100644 quickstep/res/layout/taskbar_view.xml delete mode 100644 quickstep/src/com/android/launcher3/taskbar/TaskbarIconController.java delete mode 100644 quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java delete mode 100644 quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java create mode 100644 res/layout/taskbar_view.xml diff --git a/quickstep/res/layout/taskbar.xml b/quickstep/res/layout/taskbar.xml index c4362214cb..240fe556da 100644 --- a/quickstep/res/layout/taskbar.xml +++ b/quickstep/res/layout/taskbar.xml @@ -22,29 +22,9 @@ - - - - - - + android:gravity="center"/> + + + + diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index 50453ace16..735cb24f82 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -149,5 +149,4 @@ 8dp 16dp - 16dp diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index bc2c125854..e777ee7354 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -20,6 +20,7 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_BACK_BUTTON; import static com.android.launcher3.LauncherState.FLAG_HIDE_BACK_BUTTON; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.NO_OFFSET; +import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS; import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE; @@ -29,6 +30,7 @@ import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.app.ActivityOptions; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.ServiceConnection; @@ -49,11 +51,13 @@ import com.android.launcher3.proxy.StartActivityParams; import com.android.launcher3.statehandlers.BackButtonAlphaHandler; import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.statemanager.StateManager.StateHandler; +import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarController; -import com.android.launcher3.taskbar.TaskbarManager; import com.android.launcher3.taskbar.TaskbarStateHandler; +import com.android.launcher3.taskbar.TaskbarView; import com.android.launcher3.uioverrides.RecentsViewStateController; import com.android.launcher3.util.ActivityOptionsWrapper; +import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.ObjectWrapper; import com.android.launcher3.util.UiThreadHelper; import com.android.quickstep.RecentsModel; @@ -63,7 +67,6 @@ import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.TaskUtils; import com.android.quickstep.TouchInteractionService; -import com.android.quickstep.TouchInteractionService.TISBinder; import com.android.quickstep.util.RemoteAnimationProvider; import com.android.quickstep.util.RemoteFadeOutAnimationListener; import com.android.quickstep.util.SplitSelectStateController; @@ -85,6 +88,8 @@ public abstract class BaseQuickstepLauncher extends Launcher private DepthController mDepthController = new DepthController(this); private QuickstepTransitionManager mAppTransitionManager; + private ServiceConnection mTisBinderConnection; + protected TouchInteractionService.TISBinder mTisBinder; /** * Reusable command for applying the back button alpha on the background thread. @@ -95,20 +100,8 @@ public abstract class BaseQuickstepLauncher extends Launcher private OverviewActionsView mActionsView; - private @Nullable TaskbarManager mTaskbarManager; private @Nullable TaskbarController mTaskbarController; - private final ServiceConnection mTisBinderConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName componentName, IBinder iBinder) { - mTaskbarManager = ((TISBinder) iBinder).getTaskbarManager(); - mTaskbarManager.setLauncher(BaseQuickstepLauncher.this); - } - - @Override - public void onServiceDisconnected(ComponentName componentName) { } - }; private final TaskbarStateHandler mTaskbarStateHandler = new TaskbarStateHandler(this); - // Will be updated when dragging from taskbar. private @Nullable DragOptions mNextWorkspaceDragOptions = null; private SplitPlaceholderView mSplitPlaceholderView; @@ -118,6 +111,24 @@ public abstract class BaseQuickstepLauncher extends Launcher super.onCreate(savedInstanceState); SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this); addMultiWindowModeChangedListener(mDepthController); + setupTouchInteractionServiceBinder(); + } + + private void setupTouchInteractionServiceBinder() { + Intent intent = new Intent(this, TouchInteractionService.class); + mTisBinderConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName componentName, IBinder binder) { + mTisBinder = ((TouchInteractionService.TISBinder) binder); + mTisBinder.setTaskbarOverviewProxyDelegate(mTaskbarController); + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + mTisBinder = null; + } + }; + bindService(intent, mTisBinderConnection, 0); } @Override @@ -125,12 +136,15 @@ public abstract class BaseQuickstepLauncher extends Launcher mAppTransitionManager.onActivityDestroyed(); SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this); - - - unbindService(mTisBinderConnection); - if (mTaskbarManager != null) { - mTaskbarManager.setLauncher(null); + if (mTaskbarController != null) { + mTaskbarController.cleanup(); + mTaskbarController = null; + if (mTisBinder != null) { + mTisBinder.setTaskbarOverviewProxyDelegate(null); + unbindService(mTisBinderConnection); + } } + super.onDestroy(); } @@ -257,12 +271,37 @@ public abstract class BaseQuickstepLauncher extends Launcher mAppTransitionManager = new QuickstepTransitionManager(this); mAppTransitionManager.registerRemoteAnimations(); - bindService(new Intent(this, TouchInteractionService.class), mTisBinderConnection, 0); - + addTaskbarIfNecessary(); + addOnDeviceProfileChangeListener(newDp -> addTaskbarIfNecessary()); } - public void setTaskbarController(TaskbarController taskbarController) { - mTaskbarController = taskbarController; + @Override + public void onDisplayInfoChanged(Context context, DisplayController.Info info, + int flags) { + super.onDisplayInfoChanged(context, info, flags); + if ((flags & CHANGE_ACTIVE_SCREEN) != 0) { + addTaskbarIfNecessary(); + } + } + + private void addTaskbarIfNecessary() { + if (mTaskbarController != null) { + mTaskbarController.cleanup(); + if (mTisBinder != null) { + mTisBinder.setTaskbarOverviewProxyDelegate(null); + } + mTaskbarController = null; + } + if (mDeviceProfile.isTaskbarPresent) { + TaskbarView taskbarViewOnHome = (TaskbarView) mHotseat.getTaskbarView(); + TaskbarActivityContext taskbarActivityContext = new TaskbarActivityContext(this); + mTaskbarController = new TaskbarController(this, + taskbarActivityContext.getTaskbarContainerView(), taskbarViewOnHome); + mTaskbarController.init(); + if (mTisBinder != null) { + mTisBinder.setTaskbarOverviewProxyDelegate(mTaskbarController); + } + } } public T getActionsView() { @@ -301,9 +340,14 @@ public abstract class BaseQuickstepLauncher extends Launcher } @Override + public boolean isViewInTaskbar(View v) { + return mTaskbarController != null && mTaskbarController.isViewInTaskbar(v); + } + public boolean supportsAdaptiveIconAnimation(View clickedView) { return mAppTransitionManager.hasControlRemoteAppTransitionPermission() - && FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM.get(); + && FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM.get() + && !isViewInTaskbar(clickedView); } @Override diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index 80754a00f4..1b8fcb3c67 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -1252,6 +1252,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener final boolean launchingFromWidget = mV instanceof LauncherAppWidgetHostView; final boolean launchingFromRecents = isLaunchingFromRecents(mV, appTargets); + final boolean launchingFromTaskbar = mLauncher.isViewInTaskbar(mV); if (launchingFromWidget) { composeWidgetLaunchAnimator(anim, (LauncherAppWidgetHostView) mV, appTargets, wallpaperTargets, nonAppTargets); @@ -1262,6 +1263,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener launcherClosing); addCujInstrumentation( anim, InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_RECENTS); + } else if (launchingFromTaskbar) { + // TODO } else { composeIconLaunchAnimator(anim, mV, appTargets, wallpaperTargets, nonAppTargets, launcherClosing); diff --git a/quickstep/src/com/android/launcher3/taskbar/ButtonProvider.java b/quickstep/src/com/android/launcher3/taskbar/ButtonProvider.java index 540f748313..0d4130d1bc 100644 --- a/quickstep/src/com/android/launcher3/taskbar/ButtonProvider.java +++ b/quickstep/src/com/android/launcher3/taskbar/ButtonProvider.java @@ -16,17 +16,12 @@ package com.android.launcher3.taskbar; -import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK; -import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME; -import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH; -import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS; - import android.annotation.DrawableRes; +import android.content.Context; import android.view.View; import android.widget.ImageView; import com.android.launcher3.R; -import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton; /** * Creates Buttons for Taskbar for 3 button nav. @@ -34,46 +29,47 @@ import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton; */ public class ButtonProvider { - private final int mMarginLeftRight; - private final TaskbarActivityContext mContext; + private int mMarginLeftRight; + private final Context mContext; - public ButtonProvider(TaskbarActivityContext context) { + public ButtonProvider(Context context) { mContext = context; - mMarginLeftRight = context.getResources() - .getDimensionPixelSize(R.dimen.taskbar_icon_spacing); + } + + public void setMarginLeftRight(int margin) { + mMarginLeftRight = margin; } public View getBack() { // Back button - return getButtonForDrawable(R.drawable.ic_sysbar_back, BUTTON_BACK); + return getButtonForDrawable(R.drawable.ic_sysbar_back); } public View getDown() { // Ime down button - return getButtonForDrawable(R.drawable.ic_sysbar_back, BUTTON_BACK); + return getButtonForDrawable(R.drawable.ic_sysbar_back); } public View getHome() { // Home button - return getButtonForDrawable(R.drawable.ic_sysbar_home, BUTTON_HOME); + return getButtonForDrawable(R.drawable.ic_sysbar_home); } public View getRecents() { // Recents button - return getButtonForDrawable(R.drawable.ic_sysbar_recent, BUTTON_RECENTS); + return getButtonForDrawable(R.drawable.ic_sysbar_recent); } public View getImeSwitcher() { // IME Switcher Button - return getButtonForDrawable(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH); + return getButtonForDrawable(R.drawable.ic_ime_switcher); } - private View getButtonForDrawable(@DrawableRes int drawableId, @TaskbarButton int buttonType) { + private View getButtonForDrawable(@DrawableRes int drawableId) { ImageView buttonView = new ImageView(mContext); buttonView.setImageResource(drawableId); buttonView.setBackgroundResource(R.drawable.taskbar_icon_click_feedback_roundrect); buttonView.setPadding(mMarginLeftRight, 0, mMarginLeftRight, 0); - buttonView.setOnClickListener(view -> mContext.onNavigationButtonClick(buttonType)); return buttonView; } diff --git a/quickstep/src/com/android/launcher3/taskbar/ImeBarView.java b/quickstep/src/com/android/launcher3/taskbar/ImeBarView.java index 287caab44b..bb3669beed 100644 --- a/quickstep/src/com/android/launcher3/taskbar/ImeBarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/ImeBarView.java @@ -16,6 +16,9 @@ package com.android.launcher3.taskbar; +import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK; +import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH; + import android.content.Context; import android.util.AttributeSet; import android.view.View; @@ -26,6 +29,7 @@ import com.android.launcher3.views.ActivityContext; public class ImeBarView extends RelativeLayout { private ButtonProvider mButtonProvider; + private TaskbarController.TaskbarViewCallbacks mControllerCallbacks; private View mImeView; public ImeBarView(Context context) { @@ -40,9 +44,12 @@ public class ImeBarView extends RelativeLayout { super(context, attrs, defStyleAttr); } - public void init(ButtonProvider buttonProvider) { + public void construct(ButtonProvider buttonProvider) { mButtonProvider = buttonProvider; + } + public void init(TaskbarController.TaskbarViewCallbacks taskbarCallbacks) { + mControllerCallbacks = taskbarCallbacks; ActivityContext context = getActivityContext(); RelativeLayout.LayoutParams imeParams = new RelativeLayout.LayoutParams( context.getDeviceProfile().iconSizePx, @@ -57,16 +64,24 @@ public class ImeBarView extends RelativeLayout { // Down Arrow View downView = mButtonProvider.getDown(); + downView.setOnClickListener(view -> mControllerCallbacks.onNavigationButtonClick( + BUTTON_BACK)); downView.setLayoutParams(downParams); downView.setRotation(-90); addView(downView); // IME switcher button mImeView = mButtonProvider.getImeSwitcher(); + mImeView.setOnClickListener(view -> mControllerCallbacks.onNavigationButtonClick( + BUTTON_IME_SWITCH)); mImeView.setLayoutParams(imeParams); addView(mImeView); } + public void cleanup() { + removeAllViews(); + } + public void setImeSwitcherVisibility(boolean show) { mImeView.setVisibility(show ? VISIBLE : GONE); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 70f278874a..3af51d575d 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -15,164 +15,56 @@ */ package com.android.launcher3.taskbar; -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; - -import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT; -import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR; - -import android.app.ActivityOptions; -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.Intent; -import android.content.pm.LauncherApps; -import android.graphics.PixelFormat; +import android.content.ContextWrapper; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.os.Process; -import android.os.SystemProperties; -import android.util.Log; -import android.view.ContextThemeWrapper; -import android.view.Display; -import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; -import android.view.WindowManager; -import android.widget.Toast; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; -import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.dragndrop.DraggableView; -import com.android.launcher3.folder.Folder; -import com.android.launcher3.folder.FolderIcon; -import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.model.data.WorkspaceItemInfo; -import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton; -import com.android.launcher3.touch.ItemClickHandler; -import com.android.launcher3.util.PackageManagerHelper; -import com.android.launcher3.util.Themes; -import com.android.launcher3.util.TraceHelper; import com.android.launcher3.views.ActivityContext; -import com.android.quickstep.SysUINavigationMode; -import com.android.quickstep.SysUINavigationMode.Mode; -import com.android.systemui.shared.recents.model.Task; -import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.shared.system.WindowManagerWrapper; +import com.android.launcher3.views.BaseDragLayer; /** * The {@link ActivityContext} with which we inflate Taskbar-related Views. This allows UI elements * that are used by both Launcher and Taskbar (such as Folder) to reference a generic * ActivityContext and BaseDragLayer instead of the Launcher activity and its DragLayer. */ -public class TaskbarActivityContext extends ContextThemeWrapper implements ActivityContext { - - private static final boolean ENABLE_THREE_BUTTON_TASKBAR = - SystemProperties.getBoolean("persist.debug.taskbar_three_button", false); - private static final String TAG = "TaskbarActivityContext"; - - private static final String WINDOW_TITLE = "Taskbar"; +public class TaskbarActivityContext extends ContextWrapper implements ActivityContext { private final DeviceProfile mDeviceProfile; private final LayoutInflater mLayoutInflater; private final TaskbarContainerView mTaskbarContainerView; - private final TaskbarIconController mIconController; private final MyDragController mDragController; - private final WindowManager mWindowManager; - private WindowManager.LayoutParams mWindowLayoutParams; - - private final SysUINavigationMode.Mode mNavMode; - private final TaskbarNavButtonController mNavButtonController; - - private final boolean mIsSafeModeEnabled; - - @NonNull - private TaskbarUIController mUIController = TaskbarUIController.DEFAULT; - - private final View.OnClickListener mOnTaskbarIconClickListener; - private final View.OnLongClickListener mOnTaskbarIconLongClickListener; - - public TaskbarActivityContext(Context windowContext, DeviceProfile dp, - TaskbarNavButtonController buttonController) { - super(windowContext, Themes.getActivityThemeRes(windowContext)); - mDeviceProfile = dp; - mNavButtonController = buttonController; - mNavMode = SysUINavigationMode.getMode(windowContext); - mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode", - () -> getPackageManager().isSafeMode()); - - mOnTaskbarIconLongClickListener = - new TaskbarDragController(this)::startSystemDragOnLongClick; - mOnTaskbarIconClickListener = this::onTaskbarIconClicked; - + public TaskbarActivityContext(BaseQuickstepLauncher launcher) { + super(launcher); + mDeviceProfile = launcher.getDeviceProfile().copy(this); float taskbarIconSize = getResources().getDimension(R.dimen.taskbar_icon_size); float iconScale = taskbarIconSize / mDeviceProfile.iconSizePx; mDeviceProfile.updateIconSize(iconScale, getResources()); mLayoutInflater = LayoutInflater.from(this).cloneInContext(this); + mTaskbarContainerView = (TaskbarContainerView) mLayoutInflater .inflate(R.layout.taskbar, null, false); - mIconController = new TaskbarIconController(this, mTaskbarContainerView); mDragController = new MyDragController(this); - - Display display = windowContext.getDisplay(); - Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY - ? windowContext.getApplicationContext() - : windowContext.getApplicationContext().createDisplayContext(display); - mWindowManager = c.getSystemService(WindowManager.class); } - public void init() { - mWindowLayoutParams = new WindowManager.LayoutParams( - MATCH_PARENT, - mDeviceProfile.taskbarSize, - TYPE_APPLICATION_OVERLAY, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, - PixelFormat.TRANSLUCENT); - mWindowLayoutParams.setTitle(WINDOW_TITLE); - mWindowLayoutParams.packageName = getPackageName(); - mWindowLayoutParams.gravity = Gravity.BOTTOM; - mWindowLayoutParams.setFitInsetsTypes(0); - mWindowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; - mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; - mWindowLayoutParams.setSystemApplicationOverlay(true); - - WindowManagerWrapper wmWrapper = WindowManagerWrapper.getInstance(); - wmWrapper.setProvidesInsetsTypes( - mWindowLayoutParams, - new int[] { ITYPE_EXTRA_NAVIGATION_BAR, ITYPE_BOTTOM_TAPPABLE_ELEMENT } - ); - - mIconController.init(mOnTaskbarIconClickListener, mOnTaskbarIconLongClickListener); - mWindowManager.addView(mTaskbarContainerView, mWindowLayoutParams); - } - - /** - * Updates the TaskbarContainer height (pass deviceProfile.taskbarSize to reset). - */ - public void setTaskbarWindowHeight(int height) { - if (mWindowLayoutParams.height == height) { - return; - } - mWindowLayoutParams.height = height; - mWindowManager.updateViewLayout(mTaskbarContainerView, mWindowLayoutParams); - } - - public boolean canShowNavButtons() { - return ENABLE_THREE_BUTTON_TASKBAR && mNavMode == Mode.THREE_BUTTONS; + public TaskbarContainerView getTaskbarContainerView() { + return mTaskbarContainerView; } @Override @@ -181,7 +73,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ } @Override - public TaskbarContainerView getDragLayer() { + public BaseDragLayer getDragLayer() { return mTaskbarContainerView; } @@ -200,103 +92,6 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ return mDragController; } - /** - * Sets a new data-source for this taskbar instance - */ - public void setUIController(@NonNull TaskbarUIController uiController) { - mUIController.onDestroy(); - mUIController = uiController; - mIconController.setUIController(mUIController); - mUIController.onCreate(); - } - - /** - * Called when this instance of taskbar is no longer needed - */ - public void onDestroy() { - setUIController(TaskbarUIController.DEFAULT); - mIconController.onDestroy(); - mWindowManager.removeViewImmediate(mTaskbarContainerView); - } - - void onNavigationButtonClick(@TaskbarButton int buttonType) { - mNavButtonController.onButtonClick(buttonType); - } - - public TaskbarIconController getIconController() { - return mIconController; - } - - /** - * Updates the TaskbarContainer to MATCH_PARENT vs original Taskbar size. - */ - protected void setTaskbarWindowFullscreen(boolean fullscreen) { - setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : getDeviceProfile().taskbarSize); - } - - protected void onTaskbarIconClicked(View view) { - Object tag = view.getTag(); - if (tag instanceof Task) { - Task task = (Task) tag; - ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key, - ActivityOptions.makeBasic()); - } else if (tag instanceof FolderInfo) { - FolderIcon folderIcon = (FolderIcon) view; - Folder folder = folderIcon.getFolder(); - setTaskbarWindowFullscreen(true); - - getDragLayer().post(() -> { - folder.animateOpen(); - - folder.iterateOverItems((itemInfo, itemView) -> { - itemView.setOnClickListener(mOnTaskbarIconClickListener); - itemView.setOnLongClickListener(mOnTaskbarIconLongClickListener); - // To play haptic when dragging, like other Taskbar items do. - itemView.setHapticFeedbackEnabled(true); - return false; - }); - }); - } else if (tag instanceof WorkspaceItemInfo) { - WorkspaceItemInfo info = (WorkspaceItemInfo) tag; - if (info.isDisabled()) { - ItemClickHandler.handleDisabledItemClicked(info, this); - } else { - Intent intent = new Intent(info.getIntent()) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - if (mIsSafeModeEnabled && !PackageManagerHelper.isSystemApp(this, intent)) { - Toast.makeText(this, R.string.safemode_shortcut_error, - Toast.LENGTH_SHORT).show(); - } else if (info.isPromise()) { - intent = new PackageManagerHelper(this) - .getMarketIntent(info.getTargetPackage()) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - - } else if (info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) { - String id = info.getDeepShortcutId(); - String packageName = intent.getPackage(); - getSystemService(LauncherApps.class) - .startShortcut(packageName, id, null, null, info.user); - } else if (info.user.equals(Process.myUserHandle())) { - startActivity(intent); - } else { - getSystemService(LauncherApps.class).startMainActivity( - intent.getComponent(), info.user, intent.getSourceBounds(), null); - } - } catch (NullPointerException | ActivityNotFoundException | SecurityException e) { - Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT) - .show(); - Log.e(TAG, "Unable to launch. tag=" + info + " intent=" + intent, e); - } - } - } else { - Log.e(TAG, "Unknown type clicked: " + tag); - } - - AbstractFloatingView.closeAllOpenViews(this); - } - private static class MyDragController extends DragController { MyDragController(TaskbarActivityContext activity) { super(activity); @@ -311,8 +106,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ } @Override - protected void exitDrag() { - } + protected void exitDrag() { } @Override protected DropTarget getDefaultDropTarget(int[] dropCoordinates) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java index 815efb9728..29f6935f8a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java @@ -21,7 +21,6 @@ import android.animation.Animator; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.Utilities; -import com.android.launcher3.taskbar.TaskbarController.TaskbarAnimationControllerCallbacks; import com.android.quickstep.AnimatedFloat; import com.android.quickstep.SystemUiProxy; import com.android.systemui.shared.system.QuickStepContract; @@ -35,7 +34,7 @@ public class TaskbarAnimationController { private static final long IME_VISIBILITY_ALPHA_DURATION = 120; private final BaseQuickstepLauncher mLauncher; - private final TaskbarAnimationControllerCallbacks mTaskbarCallbacks; + private final TaskbarController.TaskbarAnimationControllerCallbacks mTaskbarCallbacks; // Background alpha. private final AnimatedFloat mTaskbarBackgroundAlpha = new AnimatedFloat( @@ -56,7 +55,7 @@ public class TaskbarAnimationController { this::updateTranslationY); public TaskbarAnimationController(BaseQuickstepLauncher launcher, - TaskbarAnimationControllerCallbacks taskbarCallbacks) { + TaskbarController.TaskbarAnimationControllerCallbacks taskbarCallbacks) { mLauncher = launcher; mTaskbarCallbacks = taskbarCallbacks; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java index 5034791f0e..621bba7e85 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java @@ -15,6 +15,9 @@ */ package com.android.launcher3.taskbar; +import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_FRAME; +import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION; + import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; @@ -29,21 +32,22 @@ import com.android.launcher3.R; import com.android.launcher3.util.TouchController; import com.android.launcher3.views.BaseDragLayer; import com.android.systemui.shared.system.ViewTreeObserverWrapper; -import com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo; -import com.android.systemui.shared.system.ViewTreeObserverWrapper.OnComputeInsetsListener; /** * Top-level ViewGroup that hosts the TaskbarView as well as Views created by it such as Folder. */ public class TaskbarContainerView extends BaseDragLayer { + private final int[] mTempLoc = new int[2]; private final int mFolderMargin; private final Paint mTaskbarBackgroundPaint; - private TaskbarIconController.Callbacks mControllerCallbacks; - private TaskbarView mTaskbarView; + // Initialized in TaskbarController constructor. + private TaskbarController.TaskbarContainerViewCallbacks mControllerCallbacks; - private final OnComputeInsetsListener mTaskbarInsetsComputer = this::onComputeTaskbarInsets; + // Initialized in init. + private TaskbarView mTaskbarView; + private ViewTreeObserverWrapper.OnComputeInsetsListener mTaskbarInsetsComputer; public TaskbarContainerView(@NonNull Context context) { this(context, null); @@ -64,6 +68,15 @@ public class TaskbarContainerView extends BaseDragLayer mFolderMargin = getResources().getDimensionPixelSize(R.dimen.taskbar_folder_margin); mTaskbarBackgroundPaint = new Paint(); mTaskbarBackgroundPaint.setColor(getResources().getColor(R.color.taskbar_background)); + } + + protected void construct(TaskbarController.TaskbarContainerViewCallbacks callbacks) { + mControllerCallbacks = callbacks; + } + + protected void init(TaskbarView taskbarView) { + mTaskbarView = taskbarView; + mTaskbarInsetsComputer = createTaskbarInsetsComputer(); recreateControllers(); } @@ -72,24 +85,46 @@ public class TaskbarContainerView extends BaseDragLayer mControllers = new TouchController[0]; } - public void init(TaskbarIconController.Callbacks callbacks, TaskbarView taskbarView) { - mControllerCallbacks = callbacks; - mTaskbarView = taskbarView; + private ViewTreeObserverWrapper.OnComputeInsetsListener createTaskbarInsetsComputer() { + return insetsInfo -> { + if (mControllerCallbacks.isTaskbarTouchable()) { + // Accept touches anywhere in our bounds. + insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME); + } else { + // Let touches pass through us. + insetsInfo.touchableRegion.setEmpty(); + insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); + } + + // TaskbarContainerView provides insets to other apps based on contentInsets. These + // insets should stay consistent even if we expand TaskbarContainerView's bounds, e.g. + // to show a floating view like Folder. Thus, we set the contentInsets to be where + // mTaskbarView is, since its position never changes and insets rather than overlays. + int[] loc = mTempLoc; + float scale = mTaskbarView.getScaleX(); + float translationY = mTaskbarView.getTranslationY(); + mTaskbarView.setScaleX(1); + mTaskbarView.setScaleY(1); + mTaskbarView.setTranslationY(0); + mTaskbarView.getLocationInWindow(loc); + mTaskbarView.setScaleX(scale); + mTaskbarView.setScaleY(scale); + mTaskbarView.setTranslationY(translationY); + insetsInfo.contentInsets.left = loc[0]; + insetsInfo.contentInsets.top = loc[1]; + insetsInfo.contentInsets.right = getWidth() - (loc[0] + mTaskbarView.getWidth()); + insetsInfo.contentInsets.bottom = getHeight() - (loc[1] + mTaskbarView.getHeight()); + }; } - private void onComputeTaskbarInsets(InsetsInfo insetsInfo) { - if (mControllerCallbacks != null) { - mControllerCallbacks.updateInsetsTouchability(insetsInfo); - } - } - - protected void onDestroy() { + protected void cleanup() { ViewTreeObserverWrapper.removeOnComputeInsetsListener(mTaskbarInsetsComputer); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); + ViewTreeObserverWrapper.addOnComputeInsetsListener(getViewTreeObserver(), mTaskbarInsetsComputer); } @@ -98,7 +133,7 @@ public class TaskbarContainerView extends BaseDragLayer protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - onDestroy(); + cleanup(); } @Override @@ -108,25 +143,10 @@ public class TaskbarContainerView extends BaseDragLayer return true; } - public void updateImeBarVisibilityAlpha(float alpha) { - if (mControllerCallbacks != null) { - mControllerCallbacks.updateImeBarVisibilityAlpha(alpha); - } - } - @Override public void onViewRemoved(View child) { super.onViewRemoved(child); - if (mControllerCallbacks != null) { - mControllerCallbacks.onContainerViewRemoved(); - } - } - - @Override - protected void dispatchDraw(Canvas canvas) { - canvas.drawRect(0, canvas.getHeight() - mTaskbarView.getHeight(), canvas.getWidth(), - canvas.getHeight(), mTaskbarBackgroundPaint); - super.dispatchDraw(canvas); + mControllerCallbacks.onViewRemoved(); } /** @@ -138,6 +158,16 @@ public class TaskbarContainerView extends BaseDragLayer return boundingBox; } + protected TaskbarActivityContext getTaskbarActivityContext() { + return mActivity; + } + + @Override + protected void dispatchDraw(Canvas canvas) { + canvas.drawRect(0, canvas.getHeight() - mTaskbarView.getHeight(), canvas.getWidth(), + canvas.getHeight(), mTaskbarBackgroundPaint); + super.dispatchDraw(canvas); + } /** * Sets the alpha of the background color behind all the Taskbar contents. diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java index cdae5beb9a..6084e10d85 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java @@ -15,83 +15,105 @@ */ package com.android.launcher3.taskbar; +import static android.view.View.GONE; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + +import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT; +import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.app.ActivityOptions; +import android.graphics.PixelFormat; +import android.graphics.Point; import android.graphics.Rect; -import android.graphics.RectF; +import android.inputmethodservice.InputMethodService; +import android.view.Gravity; import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; import androidx.annotation.Nullable; +import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherState; import com.android.launcher3.QuickstepTransitionManager; import com.android.launcher3.R; -import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AlphaUpdateListener; import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.folder.Folder; +import com.android.launcher3.folder.FolderIcon; +import com.android.launcher3.model.data.FolderInfo; +import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.states.StateAnimationConfig; - +import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton; +import com.android.launcher3.touch.ItemClickHandler; +import com.android.launcher3.views.ActivityContext; +import com.android.quickstep.AnimatedFloat; +import com.android.quickstep.SysUINavigationMode; +import com.android.quickstep.TouchInteractionService.TaskbarOverviewProxyDelegate; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.WindowManagerWrapper; /** - * A data source which integrates with a Launcher instance - * TODO: Rename to have Launcher prefix + * Interfaces with Launcher/WindowManager/SystemUI to determine what to show in TaskbarView. */ +public class TaskbarController implements TaskbarOverviewProxyDelegate { -public class TaskbarController extends TaskbarUIController { + private static final String WINDOW_TITLE = "Taskbar"; + + private final TaskbarContainerView mTaskbarContainerView; + private final TaskbarView mTaskbarViewInApp; + private final TaskbarView mTaskbarViewOnHome; + private final ImeBarView mImeBarView; private final BaseQuickstepLauncher mLauncher; + private final WindowManager mWindowManager; + // Layout width and height of the Taskbar in the default state. + private final Point mTaskbarSize; private final TaskbarStateHandler mTaskbarStateHandler; private final TaskbarAnimationController mTaskbarAnimationController; private final TaskbarHotseatController mHotseatController; + private final TaskbarDragController mDragController; + private final TaskbarNavButtonController mNavButtonController; - private final TaskbarActivityContext mContext; - final TaskbarContainerView mTaskbarContainerView; - final TaskbarView mTaskbarView; + // Initialized in init(). + private WindowManager.LayoutParams mWindowLayoutParams; + private SysUINavigationMode.Mode mNavMode = SysUINavigationMode.Mode.NO_BUTTON; + private final SysUINavigationMode.NavigationModeChangeListener mNavigationModeChangeListener = + this::onNavModeChanged; private @Nullable Animator mAnimator; private boolean mIsAnimatingToLauncher; - public TaskbarController(BaseQuickstepLauncher launcher, TaskbarActivityContext context) { - mContext = context; - mTaskbarContainerView = context.getDragLayer(); - mTaskbarView = mTaskbarContainerView.findViewById(R.id.taskbar_view); - + public TaskbarController(BaseQuickstepLauncher launcher, + TaskbarContainerView taskbarContainerView, TaskbarView taskbarViewOnHome) { mLauncher = launcher; + mTaskbarContainerView = taskbarContainerView; + mTaskbarContainerView.construct(createTaskbarContainerViewCallbacks()); + ButtonProvider buttonProvider = new ButtonProvider(launcher); + mTaskbarViewInApp = mTaskbarContainerView.findViewById(R.id.taskbar_view); + mTaskbarViewInApp.construct(createTaskbarViewCallbacks(), buttonProvider); + mTaskbarViewOnHome = taskbarViewOnHome; + mTaskbarViewOnHome.construct(createTaskbarViewCallbacks(), buttonProvider); + mImeBarView = mTaskbarContainerView.findViewById(R.id.ime_bar_view); + mImeBarView.construct(buttonProvider); + mNavButtonController = new TaskbarNavButtonController(launcher); + mWindowManager = mLauncher.getWindowManager(); + mTaskbarSize = new Point(MATCH_PARENT, mLauncher.getDeviceProfile().taskbarSize); mTaskbarStateHandler = mLauncher.getTaskbarStateHandler(); mTaskbarAnimationController = new TaskbarAnimationController(mLauncher, createTaskbarAnimationControllerCallbacks()); - mHotseatController = new TaskbarHotseatController( - mLauncher, mTaskbarView::updateHotseatItems); - } - - @Override - protected void onCreate() { - mTaskbarStateHandler.setAnimationController(mTaskbarAnimationController); - mTaskbarAnimationController.init(); - mHotseatController.init(); - setTaskbarViewVisible(!mLauncher.hasBeenResumed()); - alignRealHotseatWithTaskbar(); - mLauncher.setTaskbarController(this); - } - - @Override - protected void onDestroy() { - if (mAnimator != null) { - // End this first, in case it relies on properties that are about to be cleaned up. - mAnimator.end(); - } - mTaskbarStateHandler.setAnimationController(null); - mTaskbarAnimationController.cleanup(); - mHotseatController.cleanup(); - setTaskbarViewVisible(true); - mLauncher.getHotseat().setIconsAlpha(1f); - mLauncher.setTaskbarController(null); - } - - @Override - protected boolean isTaskbarTouchable() { - return !mIsAnimatingToLauncher; + mHotseatController = new TaskbarHotseatController(mLauncher, + createTaskbarHotseatControllerCallbacks()); + mDragController = new TaskbarDragController(mLauncher); } private TaskbarAnimationControllerCallbacks createTaskbarAnimationControllerCallbacks() { @@ -103,34 +125,245 @@ public class TaskbarController extends TaskbarUIController { @Override public void updateTaskbarVisibilityAlpha(float alpha) { - mTaskbarView.setAlpha(alpha); + mTaskbarViewInApp.setAlpha(alpha); + mTaskbarViewOnHome.setAlpha(alpha); } @Override public void updateImeBarVisibilityAlpha(float alpha) { - mTaskbarContainerView.updateImeBarVisibilityAlpha(alpha); + if (mNavMode != SysUINavigationMode.Mode.THREE_BUTTONS) { + // TODO Remove sysui IME bar for gesture nav as well + return; + } + mImeBarView.setAlpha(alpha); + mImeBarView.setVisibility(alpha == 0 ? GONE : VISIBLE); } @Override public void updateTaskbarScale(float scale) { - mTaskbarView.setScaleX(scale); - mTaskbarView.setScaleY(scale); + mTaskbarViewInApp.setScaleX(scale); + mTaskbarViewInApp.setScaleY(scale); } @Override public void updateTaskbarTranslationY(float translationY) { if (translationY < 0) { // Resize to accommodate the max translation we'll reach. - mContext.setTaskbarWindowHeight(mContext.getDeviceProfile().taskbarSize + setTaskbarWindowHeight(mTaskbarSize.y + mLauncher.getHotseat().getTaskbarOffsetY()); } else { - mContext.setTaskbarWindowHeight(mContext.getDeviceProfile().taskbarSize); + setTaskbarWindowHeight(mTaskbarSize.y); } - mTaskbarView.setTranslationY(translationY); + mTaskbarViewInApp.setTranslationY(translationY); } }; } + private TaskbarContainerViewCallbacks createTaskbarContainerViewCallbacks() { + return new TaskbarContainerViewCallbacks() { + @Override + public void onViewRemoved() { + // Ensure no other children present (like Folders, etc) + for (int i = 0; i < mTaskbarContainerView.getChildCount(); i++) { + View v = mTaskbarContainerView.getChildAt(i); + if (!((v instanceof TaskbarView) || (v instanceof ImeBarView))){ + return; + } + } + setTaskbarWindowFullscreen(false); + } + + @Override + public boolean isTaskbarTouchable() { + return mTaskbarContainerView.getAlpha() > AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD + && (mTaskbarViewInApp.getVisibility() == VISIBLE + || mImeBarView.getVisibility() == VISIBLE) + && !mIsAnimatingToLauncher; + } + }; + } + + private TaskbarViewCallbacks createTaskbarViewCallbacks() { + return new TaskbarViewCallbacks() { + @Override + public View.OnClickListener getItemOnClickListener() { + return view -> { + Object tag = view.getTag(); + if (tag instanceof Task) { + Task task = (Task) tag; + ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key, + ActivityOptions.makeBasic()); + } else if (tag instanceof FolderInfo) { + FolderIcon folderIcon = (FolderIcon) view; + Folder folder = folderIcon.getFolder(); + + setTaskbarWindowFullscreen(true); + + mTaskbarContainerView.post(() -> { + folder.animateOpen(); + + folder.iterateOverItems((itemInfo, itemView) -> { + itemView.setOnClickListener(getItemOnClickListener()); + itemView.setOnLongClickListener(getItemOnLongClickListener()); + // To play haptic when dragging, like other Taskbar items do. + itemView.setHapticFeedbackEnabled(true); + return false; + }); + }); + } else { + ItemClickHandler.INSTANCE.onClick(view); + } + + AbstractFloatingView.closeAllOpenViews( + mTaskbarContainerView.getTaskbarActivityContext()); + }; + } + + @Override + public View.OnLongClickListener getItemOnLongClickListener() { + return mDragController::startSystemDragOnLongClick; + } + + @Override + public int getEmptyHotseatViewVisibility(TaskbarView taskbarView) { + // When on the home screen, we want the empty hotseat views to take up their full + // space so that the others line up with the home screen hotseat. + boolean isOnHomeScreen = taskbarView == mTaskbarViewOnHome + || mLauncher.hasBeenResumed() || mIsAnimatingToLauncher; + return isOnHomeScreen ? INVISIBLE : GONE; + } + + @Override + public float getNonIconScale(TaskbarView taskbarView) { + return taskbarView == mTaskbarViewOnHome ? getTaskbarScaleOnHome() : 1f; + } + + @Override + public void onItemPositionsChanged(TaskbarView taskbarView) { + if (taskbarView == mTaskbarViewOnHome) { + alignRealHotseatWithTaskbar(); + } + } + + @Override + public void onNavigationButtonClick(@TaskbarButton int buttonType) { + mNavButtonController.onButtonClick(buttonType); + } + }; + } + + private TaskbarHotseatControllerCallbacks createTaskbarHotseatControllerCallbacks() { + return new TaskbarHotseatControllerCallbacks() { + @Override + public void updateHotseatItems(ItemInfo[] hotseatItemInfos) { + mTaskbarViewInApp.updateHotseatItems(hotseatItemInfos); + } + }; + } + + /** + * Initializes the Taskbar, including adding it to the screen. + */ + public void init() { + mNavMode = SysUINavigationMode.INSTANCE.get(mLauncher) + .addModeChangeListener(mNavigationModeChangeListener); + mTaskbarViewInApp.init(mHotseatController.getNumHotseatIcons(), mNavMode); + mTaskbarViewOnHome.init(mHotseatController.getNumHotseatIcons(), mNavMode); + mTaskbarContainerView.init(mTaskbarViewInApp); + mImeBarView.init(createTaskbarViewCallbacks()); + addToWindowManager(); + mTaskbarStateHandler.setTaskbarCallbacks(createTaskbarStateHandlerCallbacks()); + mTaskbarAnimationController.init(); + mHotseatController.init(); + + setWhichTaskbarViewIsVisible(mLauncher.hasBeenResumed() + ? mTaskbarViewOnHome + : mTaskbarViewInApp); + } + + private TaskbarStateHandlerCallbacks createTaskbarStateHandlerCallbacks() { + return new TaskbarStateHandlerCallbacks() { + @Override + public AnimatedFloat getAlphaTarget() { + return mTaskbarAnimationController.getTaskbarVisibilityForLauncherState(); + } + + @Override + public AnimatedFloat getScaleTarget() { + return mTaskbarAnimationController.getTaskbarScaleForLauncherState(); + } + + @Override + public AnimatedFloat getTranslationYTarget() { + return mTaskbarAnimationController.getTaskbarTranslationYForLauncherState(); + } + }; + } + + /** + * Removes the Taskbar from the screen, and removes any obsolete listeners etc. + */ + public void cleanup() { + if (mAnimator != null) { + // End this first, in case it relies on properties that are about to be cleaned up. + mAnimator.end(); + } + + mTaskbarViewInApp.cleanup(); + mTaskbarViewOnHome.cleanup(); + mTaskbarContainerView.cleanup(); + mImeBarView.cleanup(); + removeFromWindowManager(); + mTaskbarStateHandler.setTaskbarCallbacks(null); + mTaskbarAnimationController.cleanup(); + mHotseatController.cleanup(); + + setWhichTaskbarViewIsVisible(null); + SysUINavigationMode.INSTANCE.get(mLauncher) + .removeModeChangeListener(mNavigationModeChangeListener); + } + + private void removeFromWindowManager() { + mWindowManager.removeViewImmediate(mTaskbarContainerView); + } + + private void addToWindowManager() { + final int gravity = Gravity.BOTTOM; + + mWindowLayoutParams = new WindowManager.LayoutParams( + mTaskbarSize.x, + mTaskbarSize.y, + TYPE_APPLICATION_OVERLAY, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.TRANSLUCENT); + mWindowLayoutParams.setTitle(WINDOW_TITLE); + mWindowLayoutParams.packageName = mLauncher.getPackageName(); + mWindowLayoutParams.gravity = gravity; + mWindowLayoutParams.setFitInsetsTypes(0); + mWindowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; + mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; + mWindowLayoutParams.setSystemApplicationOverlay(true); + + WindowManagerWrapper wmWrapper = WindowManagerWrapper.getInstance(); + wmWrapper.setProvidesInsetsTypes( + mWindowLayoutParams, + new int[] { ITYPE_EXTRA_NAVIGATION_BAR, ITYPE_BOTTOM_TAPPABLE_ELEMENT } + ); + + TaskbarContainerView.LayoutParams taskbarLayoutParams = + new TaskbarContainerView.LayoutParams(mTaskbarSize.x, mTaskbarSize.y); + taskbarLayoutParams.gravity = gravity; + mTaskbarViewInApp.setLayoutParams(taskbarLayoutParams); + + mWindowManager.addView(mTaskbarContainerView, mWindowLayoutParams); + } + + private void onNavModeChanged(SysUINavigationMode.Mode newMode) { + mNavMode = newMode; + cleanup(); + init(); + } + /** * Should be called from onResume() and onPause(), and animates the Taskbar accordingly. */ @@ -168,14 +401,13 @@ public class TaskbarController extends TaskbarUIController { @Override public void onAnimationStart(Animator animation) { mIsAnimatingToLauncher = true; - mTaskbarView.setHolesAllowedInLayout(true); - mTaskbarView.updateHotseatItemsVisibility(); + mTaskbarViewInApp.updateHotseatItemsVisibility(); } @Override public void onAnimationEnd(Animator animation) { mIsAnimatingToLauncher = false; - setTaskbarViewVisible(false); + setWhichTaskbarViewIsVisible(mTaskbarViewOnHome); } }); @@ -188,21 +420,44 @@ public class TaskbarController extends TaskbarUIController { anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { - mTaskbarView.updateHotseatItemsVisibility(); - setTaskbarViewVisible(true); + mTaskbarViewInApp.updateHotseatItemsVisibility(); + setWhichTaskbarViewIsVisible(mTaskbarViewInApp); } @Override public void onAnimationEnd(Animator animation) { - mTaskbarView.setHolesAllowedInLayout(false); } }); return anim.buildAnim(); } - @Override - protected void onImeVisible(TaskbarContainerView containerView, boolean isVisible) { - mTaskbarAnimationController.animateToVisibilityForIme(isVisible ? 0 : 1); + /** + * Should be called when the IME visibility changes, so we can hide/show Taskbar accordingly. + */ + public void setIsImeVisible(boolean isImeVisible) { + mTaskbarAnimationController.animateToVisibilityForIme(isImeVisible ? 0 : 1); + blockTaskbarTouchesForIme(isImeVisible); + } + + /** + * When in 3 button nav, the above doesn't get called since we prevent sysui nav bar from + * instantiating at all, which is what's responsible for sending sysui state flags over. + * + * @param vis IME visibility flag + * @param backDisposition Used to determine back button behavior for software keyboard + * See BACK_DISPOSITION_* constants in {@link InputMethodService} + */ + public void updateImeStatus(int displayId, int vis, int backDisposition, + boolean showImeSwitcher) { + if (displayId != mTaskbarContainerView.getContext().getDisplayId() || + mNavMode != SysUINavigationMode.Mode.THREE_BUTTONS) { + return; + } + + boolean imeVisible = (vis & InputMethodService.IME_VISIBLE) != 0; + mTaskbarAnimationController.animateToVisibilityForIme(imeVisible ? 0 : 1); + mImeBarView.setImeSwitcherVisibility(showImeSwitcher); + blockTaskbarTouchesForIme(imeVisible); } /** @@ -217,17 +472,24 @@ public class TaskbarController extends TaskbarUIController { * @return Whether any Taskbar item could handle the given MotionEvent if given the chance. */ public boolean isEventOverAnyTaskbarItem(MotionEvent ev) { - return mTaskbarView.isEventOverAnyItem(ev); + return mTaskbarViewInApp.isEventOverAnyItem(ev); } public boolean isDraggingItem() { - return mTaskbarView.isDraggingItem(); + return mTaskbarViewInApp.isDraggingItem() || mTaskbarViewOnHome.isDraggingItem(); + } + + /** + * @return Whether the given View is in the same window as Taskbar. + */ + public boolean isViewInTaskbar(View v) { + return mTaskbarContainerView.isAttachedToWindow() + && mTaskbarContainerView.getWindowId().equals(v.getWindowId()); } /** * Pads the Hotseat to line up exactly with Taskbar's copy of the Hotseat. */ - @Override public void alignRealHotseatWithTaskbar() { Rect hotseatBounds = new Rect(); DeviceProfile grid = mLauncher.getDeviceProfile(); @@ -236,28 +498,60 @@ public class TaskbarController extends TaskbarUIController { int hotseatTopDiff = hotseatHeight - grid.taskbarSize - taskbarOffset; int hotseatBottomDiff = taskbarOffset; - RectF hotseatBoundsF = mTaskbarView.getHotseatBounds(); - Utilities.scaleRectFAboutPivot(hotseatBoundsF, getTaskbarScaleOnHome(), - mTaskbarView.getPivotX(), mTaskbarView.getPivotY()); - hotseatBoundsF.round(hotseatBounds); + mTaskbarViewOnHome.getHotseatBounds().roundOut(hotseatBounds); mLauncher.getHotseat().setPadding(hotseatBounds.left, hotseatBounds.top + hotseatTopDiff, - mTaskbarView.getWidth() - hotseatBounds.right, - mTaskbarView.getHeight() - hotseatBounds.bottom + hotseatBottomDiff); + mTaskbarViewOnHome.getWidth() - hotseatBounds.right, + mTaskbarViewOnHome.getHeight() - hotseatBounds.bottom + hotseatBottomDiff); + } + + private void setWhichTaskbarViewIsVisible(@Nullable TaskbarView visibleTaskbar) { + mTaskbarViewInApp.setVisibility(visibleTaskbar == mTaskbarViewInApp + ? VISIBLE : INVISIBLE); + mTaskbarViewOnHome.setVisibility(visibleTaskbar == mTaskbarViewOnHome + ? VISIBLE : INVISIBLE); + mLauncher.getHotseat().setIconsAlpha(visibleTaskbar != mTaskbarViewInApp ? 1f : 0f); + } + + private void blockTaskbarTouchesForIme(boolean block) { + mTaskbarViewOnHome.setTouchesEnabled(!block); + mTaskbarViewInApp.setTouchesEnabled(!block); } /** * Returns the ratio of the taskbar icon size on home vs in an app. */ public float getTaskbarScaleOnHome() { - DeviceProfile inAppDp = mContext.getDeviceProfile(); - DeviceProfile onHomeDp = mLauncher.getDeviceProfile(); + DeviceProfile inAppDp = mTaskbarContainerView.getTaskbarActivityContext() + .getDeviceProfile(); + DeviceProfile onHomeDp = ActivityContext.lookupContext(mTaskbarViewOnHome.getContext()) + .getDeviceProfile(); return (float) onHomeDp.cellWidthPx / inAppDp.cellWidthPx; } - void setTaskbarViewVisible(boolean isVisible) { - mTaskbarView.setIconsVisibility(isVisible); - mLauncher.getHotseat().setIconsAlpha(isVisible ? 0f : 1f); + /** + * Updates the TaskbarContainer to MATCH_PARENT vs original Taskbar size. + */ + private void setTaskbarWindowFullscreen(boolean fullscreen) { + setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : mTaskbarSize.y); + } + + /** + * Updates the TaskbarContainer height (pass mTaskbarSize.y to reset). + */ + private void setTaskbarWindowHeight(int height) { + mWindowLayoutParams.width = mTaskbarSize.x; + mWindowLayoutParams.height = height; + mWindowManager.updateViewLayout(mTaskbarContainerView, mWindowLayoutParams); + } + + /** + * Contains methods that TaskbarStateHandler can call to interface with TaskbarController. + */ + protected interface TaskbarStateHandlerCallbacks { + AnimatedFloat getAlphaTarget(); + AnimatedFloat getScaleTarget(); + AnimatedFloat getTranslationYTarget(); } /** @@ -271,4 +565,32 @@ public class TaskbarController extends TaskbarUIController { void updateTaskbarScale(float scale); void updateTaskbarTranslationY(float translationY); } + + /** + * Contains methods that TaskbarContainerView can call to interface with TaskbarController. + */ + protected interface TaskbarContainerViewCallbacks { + void onViewRemoved(); + boolean isTaskbarTouchable(); + } + + /** + * Contains methods that TaskbarView can call to interface with TaskbarController. + */ + protected interface TaskbarViewCallbacks { + View.OnClickListener getItemOnClickListener(); + View.OnLongClickListener getItemOnLongClickListener(); + int getEmptyHotseatViewVisibility(TaskbarView taskbarView); + /** Returns how much to scale non-icon elements such as spacing and dividers. */ + float getNonIconScale(TaskbarView taskbarView); + void onItemPositionsChanged(TaskbarView taskbarView); + void onNavigationButtonClick(@TaskbarButton int buttonType); + } + + /** + * Contains methods that TaskbarHotseatController can call to interface with TaskbarController. + */ + protected interface TaskbarHotseatControllerCallbacks { + void updateHotseatItems(ItemInfo[] hotseatItemInfos); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java index ee44927ce4..5eb34cb360 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java @@ -20,7 +20,6 @@ import static android.view.View.VISIBLE; import android.content.ClipData; import android.content.ClipDescription; -import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; import android.content.res.Resources; @@ -30,6 +29,7 @@ import android.os.UserHandle; import android.view.DragEvent; import android.view.View; +import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.BubbleTextView; import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; @@ -43,12 +43,12 @@ import com.android.systemui.shared.system.LauncherAppsCompat; */ public class TaskbarDragController { - private final Context mContext; + private final BaseQuickstepLauncher mLauncher; private final int mDragIconSize; - public TaskbarDragController(Context context) { - mContext = context; - Resources resources = mContext.getResources(); + public TaskbarDragController(BaseQuickstepLauncher launcher) { + mLauncher = launcher; + Resources resources = mLauncher.getResources(); mDragIconSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_drag_icon_size); } @@ -63,6 +63,7 @@ public class TaskbarDragController { } BubbleTextView btv = (BubbleTextView) view; + View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view) { @Override public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) { @@ -86,7 +87,7 @@ public class TaskbarDragController { Intent intent = null; if (tag instanceof WorkspaceItemInfo) { WorkspaceItemInfo item = (WorkspaceItemInfo) tag; - LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class); + LauncherApps launcherApps = mLauncher.getSystemService(LauncherApps.class); clipDescription = new ClipDescription(item.title, new String[] { item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarHotseatController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarHotseatController.java index 91cf7efab5..68829cd0fb 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarHotseatController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarHotseatController.java @@ -26,8 +26,6 @@ import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.model.data.ItemInfo; -import java.util.function.Consumer; - /** * Works with TaskbarController to update the TaskbarView's Hotseat items. */ @@ -35,12 +33,13 @@ public class TaskbarHotseatController { private final BaseQuickstepLauncher mLauncher; private final Hotseat mHotseat; - private final Consumer mTaskbarCallbacks; + private final TaskbarController.TaskbarHotseatControllerCallbacks mTaskbarCallbacks; private final int mNumHotseatIcons; private final DragController.DragListener mDragListener = new DragController.DragListener() { @Override - public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { } + public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { + } @Override public void onDragEnd() { @@ -48,8 +47,8 @@ public class TaskbarHotseatController { } }; - public TaskbarHotseatController( - BaseQuickstepLauncher launcher, Consumer taskbarCallbacks) { + public TaskbarHotseatController(BaseQuickstepLauncher launcher, + TaskbarController.TaskbarHotseatControllerCallbacks taskbarCallbacks) { mLauncher = launcher; mHotseat = mLauncher.getHotseat(); mTaskbarCallbacks = taskbarCallbacks; @@ -86,6 +85,10 @@ public class TaskbarHotseatController { } } - mTaskbarCallbacks.accept(hotseatItemInfos); + mTaskbarCallbacks.updateHotseatItems(hotseatItemInfos); + } + + protected int getNumHotseatIcons() { + return mNumHotseatIcons; } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarIconController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarIconController.java deleted file mode 100644 index 2a37915fcf..0000000000 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarIconController.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.taskbar; - -import static android.view.View.GONE; -import static android.view.View.VISIBLE; - -import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_FRAME; -import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION; - -import android.graphics.Rect; -import android.inputmethodservice.InputMethodService; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnLongClickListener; - -import androidx.annotation.NonNull; - -import com.android.launcher3.R; -import com.android.launcher3.anim.AlphaUpdateListener; -import com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo; - -/** - * Controller for taskbar icon UI - */ -public class TaskbarIconController { - - private final Rect mTempRect = new Rect(); - - private final TaskbarActivityContext mActivity; - private final TaskbarContainerView mContainerView; - - private final TaskbarView mTaskbarView; - private final ImeBarView mImeBarView; - - @NonNull - private TaskbarUIController mUIController = TaskbarUIController.DEFAULT; - - TaskbarIconController(TaskbarActivityContext activity, TaskbarContainerView containerView) { - mActivity = activity; - mContainerView = containerView; - mTaskbarView = mContainerView.findViewById(R.id.taskbar_view); - mImeBarView = mContainerView.findViewById(R.id.ime_bar_view); - } - - public void init(OnClickListener clickListener, OnLongClickListener longClickListener) { - mContainerView.addOnLayoutChangeListener((v, a, b, c, d, e, f, g, h) -> - mUIController.alignRealHotseatWithTaskbar()); - - ButtonProvider buttonProvider = new ButtonProvider(mActivity); - mImeBarView.init(buttonProvider); - mTaskbarView.construct(clickListener, longClickListener, buttonProvider); - mTaskbarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarSize; - - mContainerView.init(new Callbacks(), mTaskbarView); - } - - public void onDestroy() { - mContainerView.onDestroy(); - } - - public void setUIController(@NonNull TaskbarUIController uiController) { - mUIController = uiController; - } - - /** - * When in 3 button nav, the above doesn't get called since we prevent sysui nav bar from - * instantiating at all, which is what's responsible for sending sysui state flags over. - * - * @param vis IME visibility flag - */ - public void updateImeStatus(int displayId, int vis, boolean showImeSwitcher) { - if (displayId != mActivity.getDisplayId() || !mActivity.canShowNavButtons()) { - return; - } - - mImeBarView.setImeSwitcherVisibility(showImeSwitcher); - setImeIsVisible((vis & InputMethodService.IME_VISIBLE) != 0); - } - - /** - * Should be called when the IME visibility changes, so we can hide/show Taskbar accordingly. - */ - public void setImeIsVisible(boolean isImeVisible) { - mTaskbarView.setTouchesEnabled(!isImeVisible); - mUIController.onImeVisible(mContainerView, isImeVisible); - } - - /** - * Callbacks for {@link TaskbarContainerView} to interact with the icon controller - */ - public class Callbacks { - - /** - * Called to update the touchable insets - */ - public void updateInsetsTouchability(InsetsInfo insetsInfo) { - insetsInfo.touchableRegion.setEmpty(); - if (mContainerView.getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) { - // Let touches pass through us. - insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); - } else if (mImeBarView.getVisibility() == VISIBLE) { - insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME); - } else if (!mUIController.isTaskbarTouchable()) { - // Let touches pass through us. - insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); - } else if (mTaskbarView.areIconsVisible()) { - // Buttons are visible, take over the full taskbar area - insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME); - } else { - if (mTaskbarView.mSystemButtonContainer.getVisibility() == VISIBLE) { - mContainerView.getDescendantRectRelativeToSelf( - mTaskbarView.mSystemButtonContainer, mTempRect); - insetsInfo.touchableRegion.set(mTempRect); - } - insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); - } - - // TaskbarContainerView provides insets to other apps based on contentInsets. These - // insets should stay consistent even if we expand TaskbarContainerView's bounds, e.g. - // to show a floating view like Folder. Thus, we set the contentInsets to be where - // mTaskbarView is, since its position never changes and insets rather than overlays. - insetsInfo.contentInsets.left = mTaskbarView.getLeft(); - insetsInfo.contentInsets.top = mTaskbarView.getTop(); - insetsInfo.contentInsets.right = mContainerView.getWidth() - mTaskbarView.getRight(); - insetsInfo.contentInsets.bottom = mContainerView.getHeight() - mTaskbarView.getBottom(); - } - - public void onContainerViewRemoved() { - int count = mContainerView.getChildCount(); - // Ensure no other children present (like Folders, etc) - for (int i = 0; i < count; i++) { - View v = mContainerView.getChildAt(i); - if (!((v instanceof TaskbarView) || (v instanceof ImeBarView))) { - return; - } - } - mActivity.setTaskbarWindowFullscreen(false); - } - - public void updateImeBarVisibilityAlpha(float alpha) { - if (!mActivity.canShowNavButtons()) { - // TODO Remove sysui IME bar for gesture nav as well - return; - } - mImeBarView.setAlpha(alpha); - mImeBarView.setVisibility(alpha == 0 ? GONE : VISIBLE); - } - } -} diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java deleted file mode 100644 index b9eec93687..0000000000 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.taskbar; - -import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; - -import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN; -import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY; -import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING; - -import android.content.Context; -import android.hardware.display.DisplayManager; -import android.inputmethodservice.InputMethodService; -import android.view.Display; - -import androidx.annotation.Nullable; - -import com.android.launcher3.BaseQuickstepLauncher; -import com.android.launcher3.DeviceProfile; -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.util.DisplayController; -import com.android.launcher3.util.DisplayController.Info; -import com.android.quickstep.SysUINavigationMode; -import com.android.quickstep.SysUINavigationMode.Mode; -import com.android.quickstep.TouchInteractionService; - -/** - * Class to manager taskbar lifecycle - */ -public class TaskbarManager implements DisplayController.DisplayInfoChangeListener, - SysUINavigationMode.NavigationModeChangeListener { - - private final Context mContext; - private final DisplayController mDisplayController; - private final SysUINavigationMode mSysUINavigationMode; - private final TaskbarNavButtonController mNavButtonController; - - private TaskbarActivityContext mTaskbarActivityContext; - private BaseQuickstepLauncher mLauncher; - - private static final int CHANGE_FLAGS = - CHANGE_ACTIVE_SCREEN | CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS; - - public TaskbarManager(TouchInteractionService service) { - mDisplayController = DisplayController.INSTANCE.get(service); - mSysUINavigationMode = SysUINavigationMode.INSTANCE.get(service); - Display display = - service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY); - mContext = service.createWindowContext(display, TYPE_APPLICATION_OVERLAY, null); - mNavButtonController = new TaskbarNavButtonController(service); - - mDisplayController.addChangeListener(this); - mSysUINavigationMode.addModeChangeListener(this); - recreateTaskbar(); - } - - @Override - public void onNavigationModeChanged(Mode newMode) { - recreateTaskbar(); - } - - @Override - public void onDisplayInfoChanged(Context context, Info info, int flags) { - if ((flags & CHANGE_FLAGS) != 0) { - recreateTaskbar(); - } - } - - private void destroyExistingTaskbar() { - if (mTaskbarActivityContext != null) { - mTaskbarActivityContext.onDestroy(); - mTaskbarActivityContext = null; - } - } - - /** - * Sets or clears a launcher to act as taskbar callback - */ - public void setLauncher(@Nullable BaseQuickstepLauncher launcher) { - mLauncher = launcher; - if (mTaskbarActivityContext != null) { - mTaskbarActivityContext.setUIController(mLauncher == null - ? TaskbarUIController.DEFAULT - : new TaskbarController(launcher, mTaskbarActivityContext)); - } - } - - private void recreateTaskbar() { - destroyExistingTaskbar(); - if (!FeatureFlags.ENABLE_TASKBAR.get()) { - return; - } - DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext); - if (!dp.isTaskbarPresent) { - return; - } - mTaskbarActivityContext = new TaskbarActivityContext( - mContext, dp.copy(mContext), mNavButtonController); - mTaskbarActivityContext.init(); - if (mLauncher != null) { - mTaskbarActivityContext.setUIController( - new TaskbarController(mLauncher, mTaskbarActivityContext)); - } - } - - /** - * See {@link com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags} - * @param systemUiStateFlags The latest SystemUiStateFlags - */ - public void onSystemUiFlagsChanged(int systemUiStateFlags) { - boolean isImeVisible = (systemUiStateFlags & SYSUI_STATE_IME_SHOWING) != 0; - if (mTaskbarActivityContext != null) { - mTaskbarActivityContext.getIconController().setImeIsVisible(isImeVisible); - } - } - - /** - * When in 3 button nav, the above doesn't get called since we prevent sysui nav bar from - * instantiating at all, which is what's responsible for sending sysui state flags over. - * - * @param vis IME visibility flag - * @param backDisposition Used to determine back button behavior for software keyboard - * See BACK_DISPOSITION_* constants in {@link InputMethodService} - */ - public void updateImeStatus(int displayId, int vis, int backDisposition, - boolean showImeSwitcher) { - if (mTaskbarActivityContext != null) { - mTaskbarActivityContext.getIconController() - .updateImeStatus(displayId, vis, showImeSwitcher); - } - } - - /** - * Called when the manager is no longer needed - */ - public void destroy() { - destroyExistingTaskbar(); - mDisplayController.removeChangeListener(this); - mSysUINavigationMode.removeModeChangeListener(this); - } -} diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java index 3b5afad691..54e1610cd1 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java @@ -16,8 +16,7 @@ package com.android.launcher3.taskbar; -import static android.view.Display.DEFAULT_DISPLAY; - +import android.content.Context; import android.content.Intent; import android.view.inputmethod.InputMethodManager; @@ -54,10 +53,11 @@ public class TaskbarNavButtonController { static final int BUTTON_RECENTS = BUTTON_HOME << 1; static final int BUTTON_IME_SWITCH = BUTTON_RECENTS << 1; - private final TouchInteractionService mService; - public TaskbarNavButtonController(TouchInteractionService service) { - mService = service; + private final Context mContext; + + public TaskbarNavButtonController(Context context) { + mContext = context; } public void onButtonClick(@TaskbarButton int buttonType) { @@ -78,13 +78,13 @@ public class TaskbarNavButtonController { } private void navigateHome() { - mService.startActivity(new Intent(Intent.ACTION_MAIN) + mContext.startActivity(new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_HOME) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); } private void navigateToOverview() { - mService.getOverviewCommandHelper() + TouchInteractionService.getInstance().getOverviewCommandHelper() .addCommand(OverviewCommandHelper.TYPE_SHOW); } @@ -93,8 +93,8 @@ public class TaskbarNavButtonController { } private void showIMESwitcher() { - mService.getSystemService(InputMethodManager.class) - .showInputMethodPickerFromSystem(true /* showAuxiliarySubtypes */, - DEFAULT_DISPLAY); + mContext.getSystemService(InputMethodManager.class).showInputMethodPickerFromSystem( + true /* showAuxiliarySubtypes */, mContext.getDisplayId()); } + } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java index a701aae088..6ea51fa5eb 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java @@ -24,52 +24,59 @@ import androidx.annotation.Nullable; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.LauncherState; import com.android.launcher3.anim.PendingAnimation; -import com.android.launcher3.anim.PropertySetter; import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.states.StateAnimationConfig; import com.android.quickstep.AnimatedFloat; /** * StateHandler to animate Taskbar according to Launcher's state machine. Does nothing if Taskbar - * isn't present (i.e. {@link #setAnimationController} is never called). + * isn't present (i.e. {@link #setTaskbarCallbacks} is never called). */ public class TaskbarStateHandler implements StateManager.StateHandler { private final BaseQuickstepLauncher mLauncher; // Contains Taskbar-related methods and fields we should aniamte. If null, don't do anything. - private @Nullable TaskbarAnimationController mAnimationController = null; + private @Nullable TaskbarController.TaskbarStateHandlerCallbacks mTaskbarCallbacks = null; public TaskbarStateHandler(BaseQuickstepLauncher launcher) { mLauncher = launcher; } - public void setAnimationController(TaskbarAnimationController callbacks) { - mAnimationController = callbacks; + public void setTaskbarCallbacks(TaskbarController.TaskbarStateHandlerCallbacks callbacks) { + mTaskbarCallbacks = callbacks; } @Override public void setState(LauncherState state) { - setState(state, PropertySetter.NO_ANIM_PROPERTY_SETTER); + if (mTaskbarCallbacks == null) { + return; + } + + AnimatedFloat alphaTarget = mTaskbarCallbacks.getAlphaTarget(); + AnimatedFloat scaleTarget = mTaskbarCallbacks.getScaleTarget(); + AnimatedFloat translationYTarget = mTaskbarCallbacks.getTranslationYTarget(); + boolean isTaskbarVisible = (state.getVisibleElements(mLauncher) & TASKBAR) != 0; + alphaTarget.updateValue(isTaskbarVisible ? 1f : 0f); + scaleTarget.updateValue(state.getTaskbarScale(mLauncher)); + translationYTarget.updateValue(state.getTaskbarTranslationY(mLauncher)); } @Override public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config, PendingAnimation animation) { - setState(toState, animation); - } - - private void setState(LauncherState toState, PropertySetter setter) { - if (mAnimationController == null) { + if (mTaskbarCallbacks == null) { return; } + AnimatedFloat alphaTarget = mTaskbarCallbacks.getAlphaTarget(); + AnimatedFloat scaleTarget = mTaskbarCallbacks.getScaleTarget(); + AnimatedFloat translationYTarget = mTaskbarCallbacks.getTranslationYTarget(); boolean isTaskbarVisible = (toState.getVisibleElements(mLauncher) & TASKBAR) != 0; - setter.setFloat(mAnimationController.getTaskbarVisibilityForLauncherState(), - AnimatedFloat.VALUE, isTaskbarVisible ? 1f : 0f, LINEAR); - setter.setFloat(mAnimationController.getTaskbarScaleForLauncherState(), - AnimatedFloat.VALUE, toState.getTaskbarScale(mLauncher), LINEAR); - setter.setFloat(mAnimationController.getTaskbarTranslationYForLauncherState(), - AnimatedFloat.VALUE, toState.getTaskbarTranslationY(mLauncher), ACCEL_DEACCEL); + animation.setFloat(alphaTarget, AnimatedFloat.VALUE, isTaskbarVisible ? 1f : 0f, LINEAR); + animation.setFloat(scaleTarget, AnimatedFloat.VALUE, toState.getTaskbarScale(mLauncher), + LINEAR); + animation.setFloat(translationYTarget, AnimatedFloat.VALUE, + toState.getTaskbarTranslationY(mLauncher), ACCEL_DEACCEL); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java deleted file mode 100644 index e16f5e65b0..0000000000 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.taskbar; - -/** - * Base class for providing different taskbar UI - */ -public class TaskbarUIController { - - public static final TaskbarUIController DEFAULT = new TaskbarUIController(); - - /** - * Pads the Hotseat to line up exactly with Taskbar's copy of the Hotseat. - */ - public void alignRealHotseatWithTaskbar() { } - - protected void onCreate() { } - - protected void onDestroy() { } - - protected boolean isTaskbarTouchable() { - return true; - } - - protected void onImeVisible(TaskbarContainerView container, boolean isVisible) { - container.updateImeBarVisibilityAlpha(isVisible ? 1 : 0); - } -} diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index c6573a639c..9e8013e63e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -15,14 +15,20 @@ */ package com.android.launcher3.taskbar; -import static android.view.View.MeasureSpec.EXACTLY; -import static android.view.View.MeasureSpec.makeMeasureSpec; +import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK; +import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME; +import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS; +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.LayoutTransition; +import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.RectF; +import android.os.SystemProperties; import android.util.AttributeSet; import android.view.DragEvent; import android.view.Gravity; @@ -45,12 +51,17 @@ import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.views.ActivityContext; +import com.android.quickstep.SysUINavigationMode; /** * Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps. */ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconParent, Insettable { + + private static final boolean ENABLE_THREE_BUTTON_TASKBAR = + SystemProperties.getBoolean("persist.debug.taskbar_three_button", false); + private final int mIconTouchSize; private final boolean mIsRtl; private final int mTouchSlop; @@ -58,16 +69,17 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa private final RectF mDelegateSlopBounds = new RectF(); private final int[] mTempOutLocation = new int[2]; - private final int mItemMarginLeftRight; - - private final TaskbarActivityContext mActivityContext; - // Initialized in TaskbarController constructor. - private View.OnClickListener mIconClickListener; - private View.OnLongClickListener mIconLongClickListener; + private TaskbarController.TaskbarViewCallbacks mControllerCallbacks; + // Scale on elements that aren't icons. + private float mNonIconScale; + private int mItemMarginLeftRight; - LinearLayout mSystemButtonContainer; - LinearLayout mHotseatIconsContainer; + // Initialized in init(). + private LayoutTransition mLayoutTransition; + private int mHotseatStartIndex; + private int mHotseatEndIndex; + private LinearLayout mButtonRegion; // Delegate touches to the closest view if within mIconTouchSize. private boolean mDelegateTargeted; @@ -79,12 +91,10 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa // Only non-null when the corresponding Folder is open. private @Nullable FolderIcon mLeaveBehindFolderIcon; + private int mNavButtonStartIndex; /** Provider of buttons added to taskbar in 3 button nav */ private ButtonProvider mButtonProvider; - private boolean mDisableRelayout; - private boolean mAreHolesAllowed; - public TaskbarView(@NonNull Context context) { this(context, null); } @@ -101,58 +111,80 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa public TaskbarView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - mActivityContext = ActivityContext.lookupContext(context); Resources resources = getResources(); mIconTouchSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_touch_size); - mItemMarginLeftRight = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing); - mIsRtl = Utilities.isRtl(resources); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mSystemButtonContainer = findViewById(R.id.system_button_layout); - mHotseatIconsContainer = findViewById(R.id.hotseat_icons_layout); + protected void construct(TaskbarController.TaskbarViewCallbacks taskbarViewCallbacks, + ButtonProvider buttonProvider) { + mControllerCallbacks = taskbarViewCallbacks; + mNonIconScale = mControllerCallbacks.getNonIconScale(this); + mItemMarginLeftRight = getResources().getDimensionPixelSize(R.dimen.taskbar_icon_spacing); + mItemMarginLeftRight = Math.round(mItemMarginLeftRight * mNonIconScale); + mButtonProvider = buttonProvider; + mButtonProvider.setMarginLeftRight(mItemMarginLeftRight); } - protected void construct(OnClickListener clickListener, OnLongClickListener longClickListener, - ButtonProvider buttonProvider) { - mIconClickListener = clickListener; - mIconLongClickListener = longClickListener; - mButtonProvider = buttonProvider; - - if (mActivityContext.canShowNavButtons()) { + protected void init(int numHotseatIcons, SysUINavigationMode.Mode newMode) { + // TODO: check if buttons on left + if (newMode == SysUINavigationMode.Mode.THREE_BUTTONS && ENABLE_THREE_BUTTON_TASKBAR) { + // 3 button + mNavButtonStartIndex = 0; createNavButtons(); } else { - mSystemButtonContainer.setVisibility(GONE); + mNavButtonStartIndex = -1; + removeNavButtons(); } - int numHotseatIcons = mActivityContext.getDeviceProfile().numShownHotseatIcons; + mHotseatStartIndex = mNavButtonStartIndex + 1; + mHotseatEndIndex = mHotseatStartIndex + numHotseatIcons - 1; updateHotseatItems(new ItemInfo[numHotseatIcons]); + + mLayoutTransition = new LayoutTransition(); + addUpdateListenerForAllLayoutTransitions(() -> { + if (getLayoutTransition() == mLayoutTransition) { + mControllerCallbacks.onItemPositionsChanged(this); + } + }); + setLayoutTransition(mLayoutTransition); } - /** - * Enables/disables empty icons in taskbar so that the layout matches with Launcher - */ - public void setHolesAllowedInLayout(boolean areHolesAllowed) { - if (mAreHolesAllowed != areHolesAllowed) { - mAreHolesAllowed = areHolesAllowed; - updateHotseatItemsVisibility(); - // TODO: Add animation + private void addUpdateListenerForAllLayoutTransitions(Runnable onUpdate) { + addUpdateListenerForLayoutTransition(LayoutTransition.CHANGE_APPEARING, onUpdate); + addUpdateListenerForLayoutTransition(LayoutTransition.CHANGE_DISAPPEARING, onUpdate); + addUpdateListenerForLayoutTransition(LayoutTransition.CHANGING, onUpdate); + addUpdateListenerForLayoutTransition(LayoutTransition.APPEARING, onUpdate); + addUpdateListenerForLayoutTransition(LayoutTransition.DISAPPEARING, onUpdate); + } + + private void addUpdateListenerForLayoutTransition(int transitionType, Runnable onUpdate) { + Animator anim = mLayoutTransition.getAnimator(transitionType); + if (anim instanceof ValueAnimator) { + ((ValueAnimator) anim).addUpdateListener(valueAnimator -> onUpdate.run()); + } else { + AnimatorSet animSet = new AnimatorSet(); + ValueAnimator updateAnim = ValueAnimator.ofFloat(0, 1); + updateAnim.addUpdateListener(valueAnimator -> onUpdate.run()); + animSet.playTogether(anim, updateAnim); + mLayoutTransition.setAnimator(transitionType, animSet); } } - private void setHolesAllowedInLayoutNoAnimation(boolean areHolesAllowed) { - if (mAreHolesAllowed != areHolesAllowed) { - mAreHolesAllowed = areHolesAllowed; - updateHotseatItemsVisibility(); - onMeasure(makeMeasureSpec(getMeasuredWidth(), EXACTLY), - makeMeasureSpec(getMeasuredHeight(), EXACTLY)); - onLayout(false, getLeft(), getTop(), getRight(), getBottom()); - } + protected void cleanup() { + endAllLayoutTransitionAnimators(); + setLayoutTransition(null); + removeAllViews(); + } + + private void endAllLayoutTransitionAnimators() { + mLayoutTransition.getAnimator(LayoutTransition.CHANGE_APPEARING).end(); + mLayoutTransition.getAnimator(LayoutTransition.CHANGE_DISAPPEARING).end(); + mLayoutTransition.getAnimator(LayoutTransition.CHANGING).end(); + mLayoutTransition.getAnimator(LayoutTransition.APPEARING).end(); + mLayoutTransition.getAnimator(LayoutTransition.DISAPPEARING).end(); } /** @@ -160,9 +192,10 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa */ protected void updateHotseatItems(ItemInfo[] hotseatItemInfos) { for (int i = 0; i < hotseatItemInfos.length; i++) { - ItemInfo hotseatItemInfo = hotseatItemInfos[ - !mIsRtl ? i : hotseatItemInfos.length - i - 1]; - View hotseatView = mHotseatIconsContainer.getChildAt(i); + ItemInfo hotseatItemInfo = hotseatItemInfos[!mIsRtl ? i + : hotseatItemInfos.length - i - 1]; + int hotseatIndex = mHotseatStartIndex + i; + View hotseatView = getChildAt(hotseatIndex); // Replace any Hotseat views with the appropriate type if it's not already that type. final int expectedLayoutResId; @@ -180,23 +213,23 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } else { expectedLayoutResId = R.layout.taskbar_app_icon; } - if (hotseatView == null - || hotseatView.getSourceLayoutResId() != expectedLayoutResId + if (hotseatView == null || hotseatView.getSourceLayoutResId() != expectedLayoutResId || needsReinflate) { - mHotseatIconsContainer.removeView(hotseatView); + removeView(hotseatView); + ActivityContext activityContext = getActivityContext(); if (isFolder) { FolderInfo folderInfo = (FolderInfo) hotseatItemInfo; FolderIcon folderIcon = FolderIcon.inflateFolderAndIcon(expectedLayoutResId, - mActivityContext, this, folderInfo); + getActivityContext(), this, folderInfo); folderIcon.setTextVisible(false); hotseatView = folderIcon; } else { hotseatView = inflate(expectedLayoutResId); } - int iconSize = mActivityContext.getDeviceProfile().iconSizePx; + int iconSize = activityContext.getDeviceProfile().iconSizePx; LayoutParams lp = new LayoutParams(iconSize, iconSize); lp.setMargins(mItemMarginLeftRight, 0, mItemMarginLeftRight, 0); - mHotseatIconsContainer.addView(hotseatView, i, lp); + addView(hotseatView, hotseatIndex, lp); } // Apply the Hotseat ItemInfos, or hide the view if there is none for a given index. @@ -204,11 +237,13 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa && hotseatItemInfo instanceof WorkspaceItemInfo) { ((BubbleTextView) hotseatView).applyFromWorkspaceItem( (WorkspaceItemInfo) hotseatItemInfo); - hotseatView.setOnClickListener(mIconClickListener); - hotseatView.setOnLongClickListener(mIconLongClickListener); + hotseatView.setOnClickListener(mControllerCallbacks.getItemOnClickListener()); + hotseatView.setOnLongClickListener( + mControllerCallbacks.getItemOnLongClickListener()); } else if (isFolder) { - hotseatView.setOnClickListener(mIconClickListener); - hotseatView.setOnLongClickListener(mIconLongClickListener); + hotseatView.setOnClickListener(mControllerCallbacks.getItemOnClickListener()); + hotseatView.setOnLongClickListener( + mControllerCallbacks.getItemOnLongClickListener()); } else { hotseatView.setOnClickListener(null); hotseatView.setOnLongClickListener(null); @@ -219,14 +254,24 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } protected void updateHotseatItemsVisibility() { - for (int i = mHotseatIconsContainer.getChildCount() - 1; i >= 0; i--) { - updateHotseatItemVisibility(mHotseatIconsContainer.getChildAt(i)); + for (int i = mHotseatStartIndex; i <= mHotseatEndIndex; i++) { + updateHotseatItemVisibility(getChildAt(i)); } } private void updateHotseatItemVisibility(View hotseatView) { - hotseatView.setVisibility( - hotseatView.getTag() != null ? VISIBLE : (mAreHolesAllowed ? INVISIBLE : GONE)); + if (hotseatView.getTag() != null) { + hotseatView.setVisibility(VISIBLE); + } else { + int oldVisibility = hotseatView.getVisibility(); + int newVisibility = mControllerCallbacks.getEmptyHotseatViewVisibility(this); + hotseatView.setVisibility(newVisibility); + if (oldVisibility == GONE && newVisibility != GONE) { + // By default, the layout transition only runs when going to VISIBLE, + // but we want it to run when going to GONE to INVISIBLE as well. + getLayoutTransition().showChild(this, hotseatView, oldVisibility); + } + } } @Override @@ -333,20 +378,49 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa return findDelegateView(xInOurCoordinates, yInOurCoorindates) != null; } + private void removeNavButtons() { + if (mButtonRegion != null) { + mButtonRegion.removeAllViews(); + removeView(mButtonRegion); + } // else We've never been in 3 button. Woah Scoob! + } + /** * Add back/home/recents buttons into a single ViewGroup that will be inserted at * {@param navButtonStartIndex} */ private void createNavButtons() { + ActivityContext context = getActivityContext(); + if (mButtonRegion == null) { + mButtonRegion = new LinearLayout(getContext()); + } else { + mButtonRegion.removeAllViews(); + } + mButtonRegion.setVisibility(VISIBLE); + LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams( - mActivityContext.getDeviceProfile().iconSizePx, - mActivityContext.getDeviceProfile().iconSizePx + context.getDeviceProfile().iconSizePx, + context.getDeviceProfile().iconSizePx ); buttonParams.gravity = Gravity.CENTER; - mSystemButtonContainer.addView(mButtonProvider.getBack(), buttonParams); - mSystemButtonContainer.addView(mButtonProvider.getHome(), buttonParams); - mSystemButtonContainer.addView(mButtonProvider.getRecents(), buttonParams); + View backButton = mButtonProvider.getBack(); + backButton.setOnClickListener(view -> mControllerCallbacks.onNavigationButtonClick( + BUTTON_BACK)); + mButtonRegion.addView(backButton, buttonParams); + + // Home button + View homeButton = mButtonProvider.getHome(); + homeButton.setOnClickListener(view -> mControllerCallbacks.onNavigationButtonClick( + BUTTON_HOME)); + mButtonRegion.addView(homeButton, buttonParams); + + View recentsButton = mButtonProvider.getRecents(); + recentsButton.setOnClickListener(view -> mControllerCallbacks.onNavigationButtonClick( + BUTTON_RECENTS)); + mButtonRegion.addView(recentsButton, buttonParams); + + addView(mButtonRegion, mNavButtonStartIndex); } @Override @@ -354,7 +428,7 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa switch (event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: mIsDraggingItem = true; - AbstractFloatingView.closeAllOpenViews(mActivityContext); + AbstractFloatingView.closeAllOpenViews(getActivityContext()); return true; case DragEvent.ACTION_DRAG_ENDED: mIsDraggingItem = false; @@ -371,26 +445,26 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa * @return The bounding box of where the hotseat elements are relative to this TaskbarView. */ protected RectF getHotseatBounds() { - RectF result; - mDisableRelayout = true; - boolean wereHolesAllowed = mAreHolesAllowed; - setHolesAllowedInLayoutNoAnimation(true); - result = new RectF( - mHotseatIconsContainer.getLeft(), - mHotseatIconsContainer.getTop(), - mHotseatIconsContainer.getRight(), - mHotseatIconsContainer.getBottom()); - setHolesAllowedInLayoutNoAnimation(wereHolesAllowed); - mDisableRelayout = false; - - return result; - } - - @Override - public void requestLayout() { - if (!mDisableRelayout) { - super.requestLayout(); + View firstHotseatView = null, lastHotseatView = null; + for (int i = mHotseatStartIndex; i <= mHotseatEndIndex; i++) { + View child = getChildAt(i); + if (child.getVisibility() != GONE) { + if (firstHotseatView == null) { + firstHotseatView = child; + } + lastHotseatView = child; + } } + if (firstHotseatView == null || lastHotseatView == null) { + return new RectF(); + } + View leftmostHotseatView = !mIsRtl ? firstHotseatView : lastHotseatView; + View rightmostHotseatView = !mIsRtl ? lastHotseatView : firstHotseatView; + return new RectF( + leftmostHotseatView.getLeft() - mItemMarginLeftRight, + leftmostHotseatView.getTop(), + rightmostHotseatView.getRight() + mItemMarginLeftRight, + rightmostHotseatView.getBottom()); } // FolderIconParent implemented methods. @@ -421,7 +495,7 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } private View inflate(@LayoutRes int layoutResId) { - return mActivityContext.getLayoutInflater().inflate(layoutResId, this, false); + return getActivityContext().getLayoutInflater().inflate(layoutResId, this, false); } @Override @@ -429,11 +503,7 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa // Ignore, we just implement Insettable to draw behind system insets. } - public void setIconsVisibility(boolean isVisible) { - mHotseatIconsContainer.setVisibility(isVisible ? VISIBLE : INVISIBLE); - } - - public boolean areIconsVisible() { - return mHotseatIconsContainer.getVisibility() == VISIBLE; + private T getActivityContext() { + return ActivityContext.lookupContext(getContext()); } } diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java index 86bf1194bb..f5ddd0e52f 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -52,6 +52,7 @@ import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.statemanager.BaseState; import com.android.launcher3.statemanager.StatefulActivity; +import com.android.launcher3.taskbar.TaskbarController; import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.util.WindowBounds; import com.android.launcher3.views.ScrimView; @@ -122,6 +123,11 @@ public abstract class BaseActivityInterface mTaskbarManager.updateImeStatus( - displayId, vis, backDisposition, showImeSwitcher)); + int backDisposition, boolean showImeSwitcher) throws RemoteException { + if (mTaskbarOverviewProxyDelegate == null) { + return; + } + MAIN_EXECUTOR.execute(() -> { + if (mTaskbarOverviewProxyDelegate == null) { + return; + } + mTaskbarOverviewProxyDelegate + .updateImeStatus(displayId, vis, backDisposition, showImeSwitcher); + }); } + }; - public TaskbarManager getTaskbarManager() { - return mTaskbarManager; - } + public interface TaskbarOverviewProxyDelegate { + void updateImeStatus(int displayId, int vis, int backDisposition, + boolean showImeSwitcher); } private static boolean sConnected = false; + private static TouchInteractionService sInstance; private static boolean sIsInitialized = false; private RotationTouchHelper mRotationTouchHelper; + @Nullable + private TaskbarOverviewProxyDelegate mTaskbarOverviewProxyDelegate; public static boolean isConnected() { return sConnected; } + @Nullable + public static TouchInteractionService getInstance() { + return sInstance; + } public static boolean isInitialized() { return sIsInitialized; @@ -308,7 +336,9 @@ public class TouchInteractionService extends Service implements PluginListener + + \ No newline at end of file diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 322c6eed29..3d044d68ce 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -447,6 +447,10 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, * @param canvas The canvas to draw to. */ protected void drawDotIfNecessary(Canvas canvas) { + if (mActivity instanceof Launcher && ((Launcher) mActivity).isViewInTaskbar(this)) { + // TODO: support notification dots in Taskbar + return; + } if (!mForceHideDot && (hasDot() || mDotParams.scale > 0)) { getIconBounds(mDotParams.iconBounds); Utilities.scaleRectAboutCenter(mDotParams.iconBounds, diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index ff380ce1ae..b2a9e75e50 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -49,6 +49,7 @@ public class Hotseat extends CellLayout implements Insettable { private final View mQsb; private final int mQsbHeight; + private final View mTaskbarView; private final int mTaskbarViewHeight; public Hotseat(Context context) { @@ -66,7 +67,10 @@ public class Hotseat extends CellLayout implements Insettable { mQsbHeight = mQsb.getLayoutParams().height; addView(mQsb); - mTaskbarViewHeight = context.getResources().getDimensionPixelSize(R.dimen.taskbar_size); + mTaskbarView = LayoutInflater.from(context).inflate(R.layout.taskbar_view, this, false); + mTaskbarViewHeight = mTaskbarView.getLayoutParams().height; + // We want taskbar in the back so its background applies to Hotseat as well. + addView(mTaskbarView, 0); } /** @@ -183,6 +187,8 @@ public class Hotseat extends CellLayout implements Insettable { int width = getShortcutsAndWidgets().getMeasuredWidth(); mQsb.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mQsbHeight, MeasureSpec.EXACTLY)); + mTaskbarView.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(mTaskbarViewHeight, MeasureSpec.EXACTLY)); } @Override @@ -196,6 +202,13 @@ public class Hotseat extends CellLayout implements Insettable { int bottom = b - t - getQsbOffsetY(); int top = bottom - mQsbHeight; mQsb.layout(left, top, right, bottom); + + int taskbarWidth = mTaskbarView.getMeasuredWidth(); + left = (r - l - taskbarWidth) / 2; + right = left + taskbarWidth; + bottom = b - t - getTaskbarOffsetY(); + top = bottom - mTaskbarViewHeight; + mTaskbarView.layout(left, top, right, bottom); } /** @@ -231,4 +244,10 @@ public class Hotseat extends CellLayout implements Insettable { return mQsb; } + /** + * Returns the Taskbar inside hotseat + */ + public View getTaskbarView() { + return mTaskbarView; + } } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 8889e60688..cf902160ee 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1942,6 +1942,13 @@ public class Launcher extends StatefulActivity implements Launche @Override public boolean startActivitySafely(View v, Intent intent, ItemInfo item) { + if (isViewInTaskbar(v)) { + // Start the activity without the hacky workarounds below, which assume the View was + // clicked when Launcher was resumed and will be hidden until Launcher is re-resumed + // (this isn't the case for Taskbar). + return super.startActivitySafely(v, intent, item); + } + if (!hasBeenResumed()) { // Workaround an issue where the WM launch animation is clobbered when finishing the // recents animation into launcher. Defer launching the activity until Launcher is @@ -2853,6 +2860,13 @@ public class Launcher extends StatefulActivity implements Launche .start(); } + /** + * @return Whether the View is in the same window as the Taskbar window. + */ + public boolean isViewInTaskbar(View v) { + return false; + } + public boolean supportsAdaptiveIconAnimation(View clickedView) { return false; } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 2884fba08d..7ae729aa0c 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -324,17 +324,15 @@ public final class Utilities { } public static void scaleRectFAboutCenter(RectF r, float scale) { - scaleRectFAboutPivot(r, scale, r.centerX(), r.centerY()); - } - - public static void scaleRectFAboutPivot(RectF r, float scale, float px, float py) { if (scale != 1.0f) { - r.offset(-px, -py); + float cx = r.centerX(); + float cy = r.centerY(); + r.offset(-cx, -cy); r.left = r.left * scale; r.top = r.top * scale ; r.right = r.right * scale; r.bottom = r.bottom * scale; - r.offset(px, py); + r.offset(cx, cy); } } diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java index b5dcd3a041..ce7dc07d6d 100644 --- a/src/com/android/launcher3/touch/ItemClickHandler.java +++ b/src/com/android/launcher3/touch/ItemClickHandler.java @@ -27,7 +27,6 @@ import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SU import android.app.AlertDialog; import android.app.PendingIntent; -import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.pm.LauncherApps; @@ -194,35 +193,6 @@ public class ItemClickHandler { launcher.startActivitySafely(v, intent, item); } - /** - * Handles clicking on a disabled shortcut - */ - public static void handleDisabledItemClicked(WorkspaceItemInfo shortcut, Context context) { - final int disabledFlags = shortcut.runtimeStatusFlags - & WorkspaceItemInfo.FLAG_DISABLED_MASK; - if ((disabledFlags - & ~FLAG_DISABLED_SUSPENDED - & ~FLAG_DISABLED_QUIET_USER) == 0) { - // If the app is only disabled because of the above flags, launch activity anyway. - // Framework will tell the user why the app is suspended. - } else { - if (!TextUtils.isEmpty(shortcut.disabledMessage)) { - // Use a message specific to this shortcut, if it has one. - Toast.makeText(context, shortcut.disabledMessage, Toast.LENGTH_SHORT).show(); - return; - } - // Otherwise just use a generic error message. - int error = R.string.activity_not_available; - if ((shortcut.runtimeStatusFlags & FLAG_DISABLED_SAFEMODE) != 0) { - error = R.string.safemode_shortcut_error; - } else if ((shortcut.runtimeStatusFlags & FLAG_DISABLED_BY_PUBLISHER) != 0 - || (shortcut.runtimeStatusFlags & FLAG_DISABLED_LOCKED_USER) != 0) { - error = R.string.shortcut_not_available; - } - Toast.makeText(context, error, Toast.LENGTH_SHORT).show(); - } - } - /** * Event handler for an app shortcut click. * @@ -230,8 +200,30 @@ public class ItemClickHandler { */ public static void onClickAppShortcut(View v, WorkspaceItemInfo shortcut, Launcher launcher) { if (shortcut.isDisabled()) { - handleDisabledItemClicked(shortcut, launcher); - return; + final int disabledFlags = shortcut.runtimeStatusFlags + & WorkspaceItemInfo.FLAG_DISABLED_MASK; + if ((disabledFlags & + ~FLAG_DISABLED_SUSPENDED & + ~FLAG_DISABLED_QUIET_USER) == 0) { + // If the app is only disabled because of the above flags, launch activity anyway. + // Framework will tell the user why the app is suspended. + } else { + if (!TextUtils.isEmpty(shortcut.disabledMessage)) { + // Use a message specific to this shortcut, if it has one. + Toast.makeText(launcher, shortcut.disabledMessage, Toast.LENGTH_SHORT).show(); + return; + } + // Otherwise just use a generic error message. + int error = R.string.activity_not_available; + if ((shortcut.runtimeStatusFlags & FLAG_DISABLED_SAFEMODE) != 0) { + error = R.string.safemode_shortcut_error; + } else if ((shortcut.runtimeStatusFlags & FLAG_DISABLED_BY_PUBLISHER) != 0 || + (shortcut.runtimeStatusFlags & FLAG_DISABLED_LOCKED_USER) != 0) { + error = R.string.shortcut_not_available; + } + Toast.makeText(launcher, error, Toast.LENGTH_SHORT).show(); + return; + } } // Check for abandoned promise