diff --git a/quickstep/res/layout/taskbar_all_apps.xml b/quickstep/res/layout/taskbar_all_apps.xml index 11d75c7d9b..7dc0cbe1ab 100644 --- a/quickstep/res/layout/taskbar_all_apps.xml +++ b/quickstep/res/layout/taskbar_all_apps.xml @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - - + + diff --git a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java new file mode 100644 index 0000000000..17635df355 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.taskbar; + +import android.content.Context; +import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; + +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.DeviceProfile.DeviceProfileListenable; +import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; +import com.android.launcher3.util.Themes; +import com.android.launcher3.views.ActivityContext; + +import java.util.ArrayList; +import java.util.List; + +// TODO(b/218912746): Share more behavior to avoid all apps context depending directly on taskbar. +/** Base for common behavior between taskbar window contexts. */ +public abstract class BaseTaskbarContext extends ContextThemeWrapper implements ActivityContext, + DeviceProfileListenable { + + protected final LayoutInflater mLayoutInflater; + private final List mDPChangeListeners = new ArrayList<>(); + + protected DeviceProfile mDeviceProfile; + + public BaseTaskbarContext(Context windowContext) { + super(windowContext, Themes.getActivityThemeRes(windowContext)); + mLayoutInflater = LayoutInflater.from(this).cloneInContext(this); + } + + @Override + public final LayoutInflater getLayoutInflater() { + return mLayoutInflater; + } + + @Override + public final DeviceProfile getDeviceProfile() { + return mDeviceProfile; + } + + @Override + public final List getOnDeviceProfileChangeListeners() { + return mDPChangeListeners; + } + + /** Updates the {@link DeviceProfile} instance to the latest representation of the screen. */ + public abstract void updateDeviceProfile(DeviceProfile dp); + + /** Callback invoked when a drag is initiated within this context. */ + public abstract void onDragStart(); + + /** Callback invoked when a popup is shown or closed within this context. */ + public abstract void onPopupVisibilityChanged(boolean isVisible); +} diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index fe091efecd..8f0b9345d7 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -42,10 +42,8 @@ import android.os.Process; import android.os.SystemProperties; import android.provider.Settings; import android.util.Log; -import android.view.ContextThemeWrapper; import android.view.Display; import android.view.Gravity; -import android.view.LayoutInflater; import android.view.RoundedCorner; import android.view.View; import android.view.WindowManager; @@ -58,11 +56,8 @@ import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.DeviceProfile.DeviceProfileListenable; -import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.dot.DotInfo; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; @@ -72,11 +67,10 @@ 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.popup.PopupDataProvider; +import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController; import com.android.launcher3.touch.ItemClickHandler; -import com.android.launcher3.util.OnboardingPrefs; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.SettingsCache; -import com.android.launcher3.util.Themes; import com.android.launcher3.util.TraceHelper; import com.android.launcher3.util.ViewCache; import com.android.launcher3.views.ActivityContext; @@ -89,16 +83,13 @@ import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider; import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; /** * 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, - DeviceProfileListenable { +public class TaskbarActivityContext extends BaseTaskbarContext { private static final boolean ENABLE_THREE_BUTTON_TASKBAR = SystemProperties.getBoolean("persist.debug.taskbar_three_button", false); @@ -106,13 +97,8 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ private static final String WINDOW_TITLE = "Taskbar"; - private final LayoutInflater mLayoutInflater; private final TaskbarDragLayer mDragLayer; - private final TaskbarAllAppsContainerView mAppsView; private final TaskbarControllers mControllers; - private final List mDPChangeListeners = new ArrayList<>(); - - private DeviceProfile mDeviceProfile; private final WindowManager mWindowManager; private final @Nullable RoundedCorner mLeftCorner, mRightCorner; @@ -135,14 +121,12 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ private boolean mBindingItems = false; private final TaskbarShortcutMenuAccessibilityDelegate mAccessibilityDelegate; - private final OnboardingPrefs mOnboardingPrefs; public TaskbarActivityContext(Context windowContext, DeviceProfile dp, TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider unfoldTransitionProgressProvider) { - super(windowContext, Themes.getActivityThemeRes(windowContext)); + super(windowContext); mDeviceProfile = dp; - mOnboardingPrefs = new OnboardingPrefs<>(this, Utilities.getPrefs(this)); mNavMode = SysUINavigationMode.getMode(windowContext); mImeDrawsImeNavBar = SysUINavigationMode.getImeDrawsImeNavBar(windowContext); @@ -158,8 +142,6 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ mTaskbarHeightForIme = resources.getDimensionPixelSize(R.dimen.taskbar_ime_size); - mLayoutInflater = LayoutInflater.from(this).cloneInContext(this); - // Inflate views. mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate( R.layout.taskbar, null, false); @@ -168,11 +150,6 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ FrameLayout navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view); StashedHandleView stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle); - TaskbarAllAppsSlideInView appsSlideInView = - (TaskbarAllAppsSlideInView) mLayoutInflater.inflate(R.layout.taskbar_all_apps, - mDragLayer, false); - mAppsView = appsSlideInView.getAppsView(); - Display display = windowContext.getDisplay(); Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY ? windowContext.getApplicationContext() @@ -210,7 +187,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ new TaskbarAutohideSuspendController(this), new TaskbarPopupController(this), new TaskbarForceVisibleImmersiveController(this), - new TaskbarAllAppsViewController(this, appsSlideInView)); + new TaskbarAllAppsController(this)); } public void init(TaskbarSharedState sharedState) { @@ -236,7 +213,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ mWindowManager.addView(mDragLayer, mWindowLayoutParams); } - /** Updates the Device profile instance to the latest representation of the screen. */ + @Override public void updateDeviceProfile(DeviceProfile dp) { mDeviceProfile = dp; updateIconSize(getResources()); @@ -296,31 +273,11 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ return mRightCorner == null ? 0 : mRightCorner.getRadius(); } - @Override - public LayoutInflater getLayoutInflater() { - return mLayoutInflater; - } - @Override public TaskbarDragLayer getDragLayer() { return mDragLayer; } - @Override - public TaskbarAllAppsContainerView getAppsView() { - return mAppsView; - } - - @Override - public DeviceProfile getDeviceProfile() { - return mDeviceProfile; - } - - @Override - public List getOnDeviceProfileChangeListeners() { - return mDPChangeListeners; - } - @Override public Rect getFolderBoundingBox() { return mControllers.taskbarDragLayerController.getFolderBoundingBox(); @@ -411,11 +368,6 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ return mAccessibilityDelegate; } - @Override - public OnboardingPrefs getOnboardingPrefs() { - return mOnboardingPrefs; - } - @Override public boolean isBindingItems() { return mBindingItems; @@ -425,6 +377,16 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ mBindingItems = bindingItems; } + @Override + public void onDragStart() { + setTaskbarWindowFullscreen(true); + } + + @Override + public void onPopupVisibilityChanged(boolean isVisible) { + setTaskbarWindowFocusable(isVisible); + } + /** * Sets a new data-source for this taskbar instance */ diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsViewController.java deleted file mode 100644 index 2670200342..0000000000 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsViewController.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.taskbar; - -import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT; - -import com.android.launcher3.appprediction.AppsDividerView; -import com.android.launcher3.appprediction.PredictionRowView; -import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.model.data.AppInfo; -import com.android.launcher3.model.data.ItemInfo; - -import java.util.List; - -/** Handles the {@link TaskbarAllAppsContainerView} initialization and updates. */ -public final class TaskbarAllAppsViewController { - - private final TaskbarActivityContext mContext; - private final TaskbarAllAppsSlideInView mSlideInView; - private final TaskbarAllAppsContainerView mAppsView; - - public TaskbarAllAppsViewController( - TaskbarActivityContext context, TaskbarAllAppsSlideInView slideInView) { - mContext = context; - mSlideInView = slideInView; - mAppsView = mSlideInView.getAppsView(); - } - - /** Initialize the controller. */ - public void init(TaskbarControllers controllers) { - if (!FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) { - return; - } - - mAppsView.setOnIconLongClickListener( - controllers.taskbarDragController::startDragOnLongClick); - mAppsView.getFloatingHeaderView().findFixedRowByType( - PredictionRowView.class).setOnIconLongClickListener( - controllers.taskbarDragController::startDragOnLongClick); - } - - /** Binds the current {@link AppInfo} instances to the {@link TaskbarAllAppsContainerView}. */ - public void setApps(AppInfo[] apps, int flags) { - if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) { - mAppsView.getAppsStore().setApps(apps, flags); - } - } - - /** Binds the current app predictions to all apps {@link PredictionRowView}. */ - public void setPredictedApps(List predictedApps) { - if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) { - PredictionRowView predictionRowView = - mAppsView.getFloatingHeaderView().findFixedRowByType(PredictionRowView.class); - predictionRowView.setPredictedApps(predictedApps); - } - } - - /** Opens the {@link TaskbarAllAppsContainerView}. */ - public void show() { - if (!FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) { - return; - } - - mAppsView.getFloatingHeaderView().findFixedRowByType(AppsDividerView.class) - .setShowAllAppsLabel( - !mContext.getOnboardingPrefs().hasReachedMaxCount(ALL_APPS_VISITED_COUNT)); - mContext.getOnboardingPrefs().incrementEventCount(ALL_APPS_VISITED_COUNT); - mContext.setTaskbarWindowFullscreen(true); - mSlideInView.show(); - } -} diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java index 21fbb3b2c8..d2e24e5bfa 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java @@ -20,6 +20,7 @@ import android.content.pm.ActivityInfo.Config; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController; import com.android.systemui.shared.rotation.RotationButtonController; import java.io.PrintWriter; @@ -48,7 +49,7 @@ public class TaskbarControllers { public final TaskbarAutohideSuspendController taskbarAutohideSuspendController; public final TaskbarPopupController taskbarPopupController; public final TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController; - public final TaskbarAllAppsViewController taskbarAllAppsViewController; + public final TaskbarAllAppsController taskbarAllAppsController; @Nullable private LoggableTaskbarController[] mControllersToLog = null; @@ -74,7 +75,7 @@ public class TaskbarControllers { TaskbarAutohideSuspendController taskbarAutoHideSuspendController, TaskbarPopupController taskbarPopupController, TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController, - TaskbarAllAppsViewController taskbarAllAppsViewController) { + TaskbarAllAppsController taskbarAllAppsController) { this.taskbarActivityContext = taskbarActivityContext; this.taskbarDragController = taskbarDragController; this.navButtonController = navButtonController; @@ -91,7 +92,7 @@ public class TaskbarControllers { this.taskbarAutohideSuspendController = taskbarAutoHideSuspendController; this.taskbarPopupController = taskbarPopupController; this.taskbarForceVisibleImmersiveController = taskbarForceVisibleImmersiveController; - this.taskbarAllAppsViewController = taskbarAllAppsViewController; + this.taskbarAllAppsController = taskbarAllAppsController; } /** @@ -115,7 +116,7 @@ public class TaskbarControllers { taskbarEduController.init(this); taskbarPopupController.init(this); taskbarForceVisibleImmersiveController.init(this); - taskbarAllAppsViewController.init(this); + taskbarAllAppsController.init(this); mControllersToLog = new LoggableTaskbarController[] { taskbarDragController, navButtonController, navbarButtonsViewController, diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java index 6a2f62256b..c9f7f7e528 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java @@ -75,7 +75,7 @@ import java.util.Arrays; /** * Handles long click on Taskbar items to start a system drag and drop operation. */ -public class TaskbarDragController extends DragController implements +public class TaskbarDragController extends DragController implements TaskbarControllers.LoggableTaskbarController { private static boolean DEBUG_DRAG_SHADOW_SURFACE = false; @@ -95,7 +95,7 @@ public class TaskbarDragController extends DragController { DragView dragView = startInternalDrag(btv, dragPreviewProvider); if (iconShift != null) { @@ -185,7 +184,7 @@ public class TaskbarDragController extends DragController popupContainer = + PopupContainerWithArrow popupContainer = mControllers.taskbarPopupController.showForIcon(btv); if (popupContainer != null) { dragOptions.preDragCondition = popupContainer.createPreDragCondition(false); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragView.java index cf28eff0c2..7a4243261c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragView.java @@ -25,8 +25,8 @@ import com.android.launcher3.dragndrop.DragView; * while the pre-drag is still in progress (i.e. when the long press popup is still open). After * that ends, we switch to a system drag and drop view instead. */ -public class TaskbarDragView extends DragView { - public TaskbarDragView(TaskbarActivityContext launcher, Drawable drawable, int registrationX, +public class TaskbarDragView extends DragView { + public TaskbarDragView(BaseTaskbarContext launcher, Drawable drawable, int registrationX, int registrationY, float initialScale, float scaleOnDrop, float finalScaleDps) { super(launcher, drawable, registrationX, registrationY, initialScale, scaleOnDrop, finalScaleDps); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java index 2e18a40b68..62392eea29 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java @@ -158,7 +158,7 @@ public class TaskbarModelCallbacks implements mPredictedItems = item.items; commitItemsToUI(); } else if (item.containerId == Favorites.CONTAINER_PREDICTION) { - mControllers.taskbarAllAppsViewController.setPredictedApps(item.items); + mControllers.taskbarAllAppsController.setPredictedApps(item.items); } } @@ -201,7 +201,7 @@ public class TaskbarModelCallbacks implements @Override public void bindAllApplications(AppInfo[] apps, int flags) { - mControllers.taskbarAllAppsViewController.setApps(apps, flags); + mControllers.taskbarAllAppsController.setApps(apps, flags); } protected void dumpLogs(String prefix, PrintWriter pw) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java index 68459ab4d7..ea4fe34fea 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java @@ -52,7 +52,7 @@ import java.util.stream.Stream; */ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskbarController { - private static final SystemShortcut.Factory + private static final SystemShortcut.Factory APP_INFO = SystemShortcut.AppInfo::new; private final TaskbarActivityContext mContext; @@ -121,8 +121,8 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba * Shows the notifications and deep shortcuts associated with a Taskbar {@param icon}. * @return the container if shown or null. */ - public PopupContainerWithArrow showForIcon(BubbleTextView icon) { - TaskbarActivityContext context = ActivityContext.lookupContext(icon.getContext()); + public PopupContainerWithArrow showForIcon(BubbleTextView icon) { + BaseTaskbarContext context = ActivityContext.lookupContext(icon.getContext()); if (PopupContainerWithArrow.getOpen(context) != null) { // There is already an items container open, so don't open this one. icon.clearFocus(); @@ -133,11 +133,11 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba return null; } - final PopupContainerWithArrow container = - (PopupContainerWithArrow) context.getLayoutInflater().inflate( + final PopupContainerWithArrow container = + (PopupContainerWithArrow) context.getLayoutInflater().inflate( R.layout.popup_container, context.getDragLayer(), false); container.addOnAttachStateChangeListener( - new PopupLiveUpdateHandler(mContext, container) { + new PopupLiveUpdateHandler(context, container) { @Override protected void showPopupContainerForIcon(BubbleTextView originalIcon) { showForIcon(originalIcon); @@ -157,10 +157,9 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba container.requestFocus(); // Make focusable to receive back events - mControllers.taskbarActivityContext.setTaskbarWindowFocusable(true); + context.onPopupVisibilityChanged(true); container.setOnCloseCallback(() -> { - mControllers.taskbarActivityContext.getDragLayer().post( - () -> mControllers.taskbarActivityContext.setTaskbarWindowFocusable(false)); + context.getDragLayer().post(() -> context.onPopupVisibilityChanged(false)); container.setOnCloseCallback(null); }); @@ -207,7 +206,8 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba iconShift.x = mIconLastTouchPos.x - sv.getIconCenter().x; iconShift.y = mIconLastTouchPos.y - mContext.getDeviceProfile().iconSizePx; - mControllers.taskbarDragController.startDragOnLongClick(sv, iconShift); + ((TaskbarDragController) ActivityContext.lookupContext( + v.getContext()).getDragController()).startDragOnLongClick(sv, iconShift); return false; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 335b637d8a..1d5fa4d47b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -51,11 +51,12 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba public static final int FLAG_STASHED_IN_APP_SETUP = 1 << 4; // setup wizard and AllSetActivity public static final int FLAG_STASHED_IN_APP_IME = 1 << 5; // IME is visible public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 6; + public static final int FLAG_STASHED_IN_APP_ALL_APPS = 1 << 7; // All apps is visible. // If we're in an app and any of these flags are enabled, taskbar should be stashed. private static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_MANUAL | FLAG_STASHED_IN_APP_PINNED | FLAG_STASHED_IN_APP_EMPTY | FLAG_STASHED_IN_APP_SETUP - | FLAG_STASHED_IN_APP_IME; + | FLAG_STASHED_IN_APP_IME | FLAG_STASHED_IN_APP_ALL_APPS; // If any of these flags are enabled, inset apps by our stashed height instead of our unstashed // height. This way the reported insets are consistent even during transitions out of the app. @@ -585,6 +586,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba str.add((flags & FLAG_STASHED_IN_APP_IME) != 0 ? "FLAG_STASHED_IN_APP_IME" : ""); str.add((flags & FLAG_IN_STASHED_LAUNCHER_STATE) != 0 ? "FLAG_IN_STASHED_LAUNCHER_STATE" : ""); + str.add((flags & FLAG_STASHED_IN_APP_ALL_APPS) != 0 ? "FLAG_STASHED_IN_APP_ALL_APPS" : ""); return str.toString(); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index 8b6831b8d6..153ed140b4 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -306,7 +306,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar } public View.OnClickListener getAllAppsButtonClickListener() { - return v -> mControllers.taskbarAllAppsViewController.show(); + return v -> mControllers.taskbarAllAppsController.show(); } public View.OnLongClickListener getIconOnLongClickListener() { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsContainerView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java similarity index 83% rename from quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsContainerView.java rename to quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java index d6eb71641c..b36b9f1ffd 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsContainerView.java +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.launcher3.taskbar; +package com.android.launcher3.taskbar.allapps; import android.content.Context; import android.util.AttributeSet; @@ -29,10 +29,7 @@ import com.android.launcher3.allapps.BaseAllAppsContainerView; import com.android.launcher3.allapps.search.SearchAdapterProvider; /** All apps container accessible from taskbar. */ -public class TaskbarAllAppsContainerView extends BaseAllAppsContainerView { - public TaskbarAllAppsContainerView(Context context) { - this(context, null); - } +public class TaskbarAllAppsContainerView extends BaseAllAppsContainerView { public TaskbarAllAppsContainerView(Context context, AttributeSet attrs) { this(context, attrs, 0); @@ -44,8 +41,8 @@ public class TaskbarAllAppsContainerView extends BaseAllAppsContainerView createMainAdapterProvider() { - // Task bar all apps does not yet support search, so this implementation is minimal. - return new SearchAdapterProvider(mActivityContext) { + // Taskbar all apps does not yet support search, so this implementation is minimal. + return new SearchAdapterProvider(mActivityContext) { @Override public boolean launchHighlightedItem() { return false; @@ -79,8 +76,7 @@ public class TaskbarAllAppsContainerView extends BaseAllAppsContainerView + * All apps has its own window and needs a window context. Some properties are delegated to the + * {@link TaskbarActivityContext} such as {@link DeviceProfile} and {@link PopupDataProvider}. + */ +class TaskbarAllAppsContext extends BaseTaskbarContext { + private final TaskbarActivityContext mTaskbarContext; + private final OnboardingPrefs mOnboardingPrefs; + + private final TaskbarAllAppsViewController mAllAppsViewController; + private final TaskbarDragController mDragController; + private final TaskbarAllAppsDragLayer mDragLayer; + private final TaskbarAllAppsContainerView mAppsView; + + TaskbarAllAppsContext( + TaskbarActivityContext taskbarContext, + TaskbarAllAppsController windowController, + TaskbarStashController taskbarStashController) { + super(taskbarContext.createWindowContext(TYPE_APPLICATION_OVERLAY, null)); + mTaskbarContext = taskbarContext; + mDeviceProfile = taskbarContext.getDeviceProfile(); + mDragController = new TaskbarDragController(this); + mOnboardingPrefs = new OnboardingPrefs<>(this, Utilities.getPrefs(this)); + + mDragLayer = new TaskbarAllAppsDragLayer(this); + TaskbarAllAppsSlideInView slideInView = (TaskbarAllAppsSlideInView) mLayoutInflater.inflate( + R.layout.taskbar_all_apps, mDragLayer, false); + mAllAppsViewController = new TaskbarAllAppsViewController( + this, + slideInView, + windowController, + taskbarStashController); + mAppsView = slideInView.getAppsView(); + } + + TaskbarAllAppsViewController getAllAppsViewController() { + return mAllAppsViewController; + } + + @Override + public TaskbarDragController getDragController() { + return mDragController; + } + + @Override + public TaskbarAllAppsDragLayer getDragLayer() { + return mDragLayer; + } + + @Override + public TaskbarAllAppsContainerView getAppsView() { + return mAppsView; + } + + @Override + public OnboardingPrefs getOnboardingPrefs() { + return mOnboardingPrefs; + } + + @Override + public boolean isBindingItems() { + return mTaskbarContext.isBindingItems(); + } + + @Override + public View.OnClickListener getItemOnClickListener() { + return mTaskbarContext.getItemOnClickListener(); + } + + @Override + public PopupDataProvider getPopupDataProvider() { + return mTaskbarContext.getPopupDataProvider(); + } + + @Override + public DotInfo getDotInfoForItem(ItemInfo info) { + return mTaskbarContext.getDotInfoForItem(info); + } + + @Override + public void updateDeviceProfile(DeviceProfile dp) { + mDeviceProfile = dp; + dispatchDeviceProfileChanged(); + } + + @Override + public void onDragStart() {} + + @Override + public void onPopupVisibilityChanged(boolean isVisible) {} + + /** Root drag layer for this context. */ + private static class TaskbarAllAppsDragLayer extends BaseDragLayer { + + private TaskbarAllAppsDragLayer(Context context) { + super(context, null, 1); + setClipChildren(false); + recreateControllers(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mActivity.mAllAppsViewController.show(); + } + + @Override + public void recreateControllers() { + mControllers = new TouchController[]{mActivity.mDragController}; + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) { + AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity); + if (topView != null && topView.onBackPressed()) { + return true; + } + } + return super.dispatchKeyEvent(event); + } + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java new file mode 100644 index 0000000000..93024521d4 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.taskbar.allapps; + +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; + +import androidx.annotation.Nullable; + +import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; +import com.android.launcher3.appprediction.PredictionRowView; +import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.model.data.AppInfo; +import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.taskbar.TaskbarActivityContext; +import com.android.launcher3.taskbar.TaskbarControllers; + +import java.util.List; +import java.util.Optional; + +/** + * Handles the all apps overlay window initialization, updates, and its data. + *

+ * All apps is in an application overlay window instead of taskbar's navigation bar panel window, + * because a navigation bar panel is higher than UI components that all apps should be below such as + * the notification tray. + *

+ * The all apps window is created and destroyed upon opening and closing all apps, respectively. + * Application data may be bound while the window does not exist, so this controller will store + * the models for the next all apps session. + */ +public final class TaskbarAllAppsController implements OnDeviceProfileChangeListener { + + private static final String WINDOW_TITLE = "Taskbar All Apps"; + + private final TaskbarActivityContext mTaskbarContext; + private final TaskbarAllAppsProxyView mProxyView; + private final LayoutParams mLayoutParams; + + private TaskbarControllers mControllers; + /** Window context for all apps if it is open. */ + private @Nullable TaskbarAllAppsContext mAllAppsContext; + + // Application data models. + private AppInfo[] mApps; + private int mAppsModelFlags; + private List mPredictedApps; + + public TaskbarAllAppsController(TaskbarActivityContext context) { + mTaskbarContext = context; + mProxyView = new TaskbarAllAppsProxyView(mTaskbarContext); + mLayoutParams = createLayoutParams(); + } + + /** Initialize the controller. */ + public void init(TaskbarControllers controllers) { + if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) { + mControllers = controllers; + } + } + + /** Updates the current {@link AppInfo} instances. */ + public void setApps(AppInfo[] apps, int flags) { + if (!FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) { + return; + } + + mApps = apps; + mAppsModelFlags = flags; + if (mAllAppsContext != null) { + mAllAppsContext.getAppsView().getAppsStore().setApps(mApps, mAppsModelFlags); + } + } + + /** Updates the current predictions. */ + public void setPredictedApps(List predictedApps) { + if (!FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) { + return; + } + + mPredictedApps = predictedApps; + if (mAllAppsContext != null) { + mAllAppsContext.getAppsView().getFloatingHeaderView() + .findFixedRowByType(PredictionRowView.class) + .setPredictedApps(mPredictedApps); + } + } + + /** Opens the {@link TaskbarAllAppsContainerView} in a new window. */ + public void show() { + if (mProxyView.isOpen()) { + return; + } + mProxyView.show(); + + mAllAppsContext = new TaskbarAllAppsContext(mTaskbarContext, + this, + mControllers.taskbarStashController); + mAllAppsContext.getDragController().init(mControllers); + mTaskbarContext.addOnDeviceProfileChangeListener(this); + Optional.ofNullable(mAllAppsContext.getSystemService(WindowManager.class)) + .ifPresent(m -> m.addView(mAllAppsContext.getDragLayer(), mLayoutParams)); + + mAllAppsContext.getAppsView().getAppsStore().setApps(mApps, mAppsModelFlags); + mAllAppsContext.getAppsView().getFloatingHeaderView() + .findFixedRowByType(PredictionRowView.class) + .setPredictedApps(mPredictedApps); + } + + /** + * Removes the all apps window from the hierarchy. + *

+ * This method should be called after an exit animation finishes, if applicable. + */ + void closeWindow() { + mProxyView.close(false); + mTaskbarContext.removeOnDeviceProfileChangeListener(this); + Optional.ofNullable(mAllAppsContext) + .map(c -> c.getSystemService(WindowManager.class)) + .ifPresent(m -> m.removeView(mAllAppsContext.getDragLayer())); + mAllAppsContext = null; + } + + private LayoutParams createLayoutParams() { + LayoutParams layoutParams = new LayoutParams( + TYPE_APPLICATION_OVERLAY, + 0, + PixelFormat.TRANSLUCENT); + layoutParams.setTitle(WINDOW_TITLE); + layoutParams.gravity = Gravity.BOTTOM; + layoutParams.packageName = mTaskbarContext.getPackageName(); + layoutParams.setFitInsetsTypes(0); // Handled by container view. + layoutParams.setSystemApplicationOverlay(true); + return layoutParams; + } + + @Override + public void onDeviceProfileChanged(DeviceProfile dp) { + Optional.ofNullable(mAllAppsContext).ifPresent(c -> c.updateDeviceProfile(dp)); + } + + /** + * Proxy view connecting taskbar drag layer to the all apps window. + *

+ * The all apps view is in a separate window and has its own drag layer, but this proxy lets it + * behave as though its in the taskbar drag layer. For instance, when the taskbar closes all + * {@link AbstractFloatingView} instances, the all apps window will also close. + */ + private class TaskbarAllAppsProxyView extends AbstractFloatingView { + + private TaskbarAllAppsProxyView(Context context) { + super(context, null); + } + + private void show() { + mIsOpen = true; + mTaskbarContext.getDragLayer().addView(this); + } + + @Override + protected void handleClose(boolean animate) { + mTaskbarContext.getDragLayer().removeView(this); + Optional.ofNullable(mAllAppsContext) + .map(TaskbarAllAppsContext::getAllAppsViewController) + .ifPresent(v -> v.close(animate)); + } + + @Override + protected boolean isOfType(int type) { + return (type & TYPE_TASKBAR_ALL_APPS) != 0; + } + + @Override + public boolean onControllerInterceptTouchEvent(MotionEvent ev) { + return false; + } + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java similarity index 61% rename from quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsSlideInView.java rename to quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java index 63690c4847..02aa3f208b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsSlideInView.java +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.launcher3.taskbar; +package com.android.launcher3.taskbar.allapps; import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE; @@ -23,18 +23,22 @@ import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; +import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; import com.android.launcher3.R; import com.android.launcher3.views.AbstractSlideInView; -/** Wrapper for taskbar all apps with slide-in behavior. */ -public class TaskbarAllAppsSlideInView extends - AbstractSlideInView implements Insettable { +import java.util.Optional; - private static final int DEFAULT_OPEN_DURATION = 500; - private static final int DEFAULT_CLOSE_DURATION = 200; +/** Wrapper for taskbar all apps with slide-in behavior. */ +public class TaskbarAllAppsSlideInView extends AbstractSlideInView + implements Insettable, DeviceProfile.OnDeviceProfileChangeListener { + static final int DEFAULT_OPEN_DURATION = 500; + static final int DEFAULT_CLOSE_DURATION = 200; private TaskbarAllAppsContainerView mAppsView; + private OnCloseListener mOnCloseBeginListener; + private float mShiftRange; public TaskbarAllAppsSlideInView(Context context, AttributeSet attrs) { this(context, attrs, 0); @@ -46,7 +50,7 @@ public class TaskbarAllAppsSlideInView extends } /** Opens the all apps view. */ - public void show() { + void show() { if (mIsOpen || mOpenCloseAnimator.isRunning()) { return; } @@ -60,12 +64,18 @@ public class TaskbarAllAppsSlideInView extends } /** The apps container inside this view. */ - public TaskbarAllAppsContainerView getAppsView() { + TaskbarAllAppsContainerView getAppsView() { return mAppsView; } + /** Callback invoked when the view is beginning to close (e.g. close animation is started). */ + void setOnCloseBeginListener(OnCloseListener onCloseBeginListener) { + mOnCloseBeginListener = onCloseBeginListener; + } + @Override protected void handleClose(boolean animate) { + Optional.ofNullable(mOnCloseBeginListener).ifPresent(OnCloseListener::onSlideInViewClosed); handleClose(animate, DEFAULT_CLOSE_DURATION); } @@ -79,6 +89,17 @@ public class TaskbarAllAppsSlideInView extends super.onFinishInflate(); mAppsView = findViewById(R.id.apps_view); mContent = mAppsView; + + DeviceProfile dp = mActivityContext.getDeviceProfile(); + setShiftRange(dp.allAppsShiftRange); + + mActivityContext.addOnDeviceProfileChangeListener(this); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + setTranslationShift(mTranslationShift); } @Override @@ -98,4 +119,24 @@ public class TaskbarAllAppsSlideInView extends public void setInsets(Rect insets) { mAppsView.setInsets(insets); } + + @Override + public void onDeviceProfileChanged(DeviceProfile dp) { + setShiftRange(dp.allAppsShiftRange); + setTranslationShift(TRANSLATION_SHIFT_OPENED); + } + + private void setShiftRange(float shiftRange) { + mShiftRange = shiftRange; + } + + @Override + protected float getShiftRange() { + return mShiftRange; + } + + @Override + protected boolean isEventOverContent(MotionEvent ev) { + return getPopupContainer().isEventOverView(mAppsView.getVisibleContainerView(), ev); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java new file mode 100644 index 0000000000..c1abaaca06 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.taskbar.allapps; + +import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IN_APP_ALL_APPS; +import static com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView.DEFAULT_CLOSE_DURATION; +import static com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView.DEFAULT_OPEN_DURATION; +import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT; + +import com.android.launcher3.appprediction.AppsDividerView; +import com.android.launcher3.appprediction.PredictionRowView; +import com.android.launcher3.taskbar.TaskbarStashController; + +/** + * Handles the {@link TaskbarAllAppsContainerView} behavior and synchronizes its transitions with + * taskbar stashing. + */ +final class TaskbarAllAppsViewController { + + private final TaskbarAllAppsContext mContext; + private final TaskbarAllAppsSlideInView mSlideInView; + private final TaskbarAllAppsContainerView mAppsView; + private final TaskbarStashController mTaskbarStashController; + + TaskbarAllAppsViewController( + TaskbarAllAppsContext context, + TaskbarAllAppsSlideInView slideInView, + TaskbarAllAppsController windowController, + TaskbarStashController taskbarStashController) { + + mContext = context; + mSlideInView = slideInView; + mAppsView = mSlideInView.getAppsView(); + mTaskbarStashController = taskbarStashController; + + setUpIconLongClick(); + setUpAppDivider(); + setUpTaskbarStashing(); + mSlideInView.addOnCloseListener(windowController::closeWindow); + } + + /** Starts the {@link TaskbarAllAppsSlideInView} enter transition. */ + void show() { + mSlideInView.show(); + } + + /** Closes the {@link TaskbarAllAppsSlideInView}. */ + void close(boolean animate) { + mSlideInView.close(animate); + } + + private void setUpIconLongClick() { + mAppsView.setOnIconLongClickListener( + mContext.getDragController()::startDragOnLongClick); + mAppsView.getFloatingHeaderView() + .findFixedRowByType(PredictionRowView.class) + .setOnIconLongClickListener( + mContext.getDragController()::startDragOnLongClick); + } + + private void setUpAppDivider() { + mAppsView.getFloatingHeaderView() + .findFixedRowByType(AppsDividerView.class) + .setShowAllAppsLabel(!mContext.getOnboardingPrefs().hasReachedMaxCount( + ALL_APPS_VISITED_COUNT)); + mContext.getOnboardingPrefs().incrementEventCount(ALL_APPS_VISITED_COUNT); + } + + private void setUpTaskbarStashing() { + mTaskbarStashController.updateStateForFlag(FLAG_STASHED_IN_APP_ALL_APPS, true); + mTaskbarStashController.applyState(DEFAULT_OPEN_DURATION); + mSlideInView.setOnCloseBeginListener(() -> { + mTaskbarStashController.updateStateForFlag( + FLAG_STASHED_IN_APP_ALL_APPS, false); + mTaskbarStashController.applyState(DEFAULT_CLOSE_DURATION); + }); + } +} diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java index 26d8f303e8..fec591b653 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java @@ -53,9 +53,16 @@ public class AllAppsState extends LauncherState { @Override public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) { - ScaleAndTranslation scaleAndTranslation = LauncherState.OVERVIEW - .getWorkspaceScaleAndTranslation(launcher); - scaleAndTranslation.scale = 1; + ScaleAndTranslation scaleAndTranslation = + new ScaleAndTranslation(NO_SCALE, NO_OFFSET, NO_OFFSET); + if (launcher.getDeviceProfile().isTablet) { + scaleAndTranslation.scale = 0.97f; + } else { + ScaleAndTranslation overviewScaleAndTranslation = LauncherState.OVERVIEW + .getWorkspaceScaleAndTranslation(launcher); + scaleAndTranslation.translationX = overviewScaleAndTranslation.translationX; + scaleAndTranslation.translationY = overviewScaleAndTranslation.translationY; + } return scaleAndTranslation; } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java index 099915a281..f93917f1f5 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java @@ -23,8 +23,13 @@ import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL; +import static com.android.launcher3.anim.Interpolators.FINAL_FRAME; +import static com.android.launcher3.anim.Interpolators.INSTANT; +import static com.android.launcher3.anim.Interpolators.LINEAR; +import static com.android.launcher3.anim.Interpolators.LINEAR_TELEPORT; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS; import android.view.MotionEvent; @@ -126,23 +131,31 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr private StateAnimationConfig getNormalToAllAppsAnimation() { StateAnimationConfig builder = new StateAnimationConfig(); - builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL, - ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD, - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD)); + boolean isTablet = mLauncher.getDeviceProfile().isTablet; + builder.setInterpolator(ANIM_ALL_APPS_FADE, isTablet + ? INSTANT + : Interpolators.clampToProgress(ACCEL, + ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD, + ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD)); builder.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(ACCEL, ALL_APPS_SCRIM_VISIBLE_THRESHOLD, ALL_APPS_SCRIM_OPAQUE_THRESHOLD)); + builder.setInterpolator(ANIM_VERTICAL_PROGRESS, isTablet ? LINEAR_TELEPORT : LINEAR); return builder; } private StateAnimationConfig getAllAppsToNormalAnimation() { StateAnimationConfig builder = new StateAnimationConfig(); - builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL, - 1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD, - 1 - ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD)); + boolean isTablet = mLauncher.getDeviceProfile().isTablet; + builder.setInterpolator(ANIM_ALL_APPS_FADE, isTablet + ? FINAL_FRAME + : Interpolators.clampToProgress(DEACCEL, + 1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD, + 1 - ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD)); builder.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(DEACCEL, 1 - ALL_APPS_SCRIM_OPAQUE_THRESHOLD, 1 - ALL_APPS_SCRIM_VISIBLE_THRESHOLD)); + builder.setInterpolator(ANIM_VERTICAL_PROGRESS, isTablet ? LINEAR_TELEPORT : LINEAR); return builder; } diff --git a/res/drawable/bg_rounded_corner_bottom_sheet.xml b/res/drawable/bg_rounded_corner_bottom_sheet.xml index aa49bced7a..dfcd354ce7 100644 --- a/res/drawable/bg_rounded_corner_bottom_sheet.xml +++ b/res/drawable/bg_rounded_corner_bottom_sheet.xml @@ -16,7 +16,7 @@ - + diff --git a/res/drawable/bg_all_apps_bottom_sheet.xml b/res/drawable/bg_rounded_corner_bottom_sheet_handle.xml similarity index 55% rename from res/drawable/bg_all_apps_bottom_sheet.xml rename to res/drawable/bg_rounded_corner_bottom_sheet_handle.xml index dba2fee7e9..c5021787c5 100644 --- a/res/drawable/bg_all_apps_bottom_sheet.xml +++ b/res/drawable/bg_rounded_corner_bottom_sheet_handle.xml @@ -1,6 +1,5 @@ - - - - - - - - - \ No newline at end of file + + + + + diff --git a/res/layout/all_apps_bottom_sheet_background.xml b/res/layout/all_apps_bottom_sheet_background.xml index ad10d6801b..12b6b7bb55 100644 --- a/res/layout/all_apps_bottom_sheet_background.xml +++ b/res/layout/all_apps_bottom_sheet_background.xml @@ -17,19 +17,19 @@ android:id="@+id/bottom_sheet_background" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@drawable/bg_all_apps_bottom_sheet"> + android:background="@drawable/bg_rounded_corner_bottom_sheet"> + android:layout_height="36dp" /> + android:layout_marginTop="@dimen/bottom_sheet_handle_margin" + android:layout_marginBottom="@dimen/bottom_sheet_handle_margin" + android:background="@drawable/bg_rounded_corner_bottom_sheet_handle" /> diff --git a/res/layout/widgets_bottom_sheet_content.xml b/res/layout/widgets_bottom_sheet_content.xml index 1a2cfc6f93..a5f72ef30a 100644 --- a/res/layout/widgets_bottom_sheet_content.xml +++ b/res/layout/widgets_bottom_sheet_content.xml @@ -19,16 +19,16 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/bg_rounded_corner_bottom_sheet" - android:paddingTop="16dp" + android:paddingTop="@dimen/bottom_sheet_handle_margin" android:orientation="vertical"> + android:background="@drawable/bg_rounded_corner_bottom_sheet_handle"/> + android:background="@drawable/bg_rounded_corner_bottom_sheet_handle"/> 32dp - 32dp + 0dp + 46dp 75dp diff --git a/res/values-sw720dp-land/dimens.xml b/res/values-sw720dp-land/dimens.xml new file mode 100644 index 0000000000..a9e0fb8a34 --- /dev/null +++ b/res/values-sw720dp-land/dimens.xml @@ -0,0 +1,20 @@ + + + + + + 0dp + diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml index 9d7941f5e3..5c314d598e 100644 --- a/res/values-sw720dp/dimens.xml +++ b/res/values-sw720dp/dimens.xml @@ -16,5 +16,6 @@ - 41dp + 300dp + 65dp diff --git a/res/values/dimens.xml b/res/values/dimens.xml index ddc7d10994..3e666fcf2e 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -93,8 +93,11 @@ -26dp - 320dp + 320dp + 0dp 48dp + + 24dp 30dp 40dp 144dp @@ -363,4 +366,9 @@ 32dp 8dp + + 32dp + 4dp + 16dp + 2dp diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 62703ad2e0..7189ef70ca 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -171,7 +171,8 @@ public class DeviceProfile { // All apps public Point allAppsBorderSpacePx; - public int allAppsOpenVerticalTranslate; + public int allAppsShiftRange; + public int allAppsTopPadding; public int allAppsCellHeightPx; public int allAppsCellWidthPx; public int allAppsIconSizePx; @@ -288,8 +289,11 @@ public class DeviceProfile { desiredWorkspaceHorizontalMarginPx = getHorizontalMarginPx(inv, res); desiredWorkspaceHorizontalMarginOriginalPx = desiredWorkspaceHorizontalMarginPx; - allAppsOpenVerticalTranslate = res.getDimensionPixelSize( - R.dimen.all_apps_open_vertical_translate); + allAppsTopPadding = res.getDimensionPixelSize(R.dimen.all_apps_top_padding) + + (isTablet ? heightPx - availableHeightPx : 0); + allAppsShiftRange = isTablet + ? heightPx - allAppsTopPadding + : res.getDimensionPixelSize(R.dimen.all_apps_starting_vertical_translate); folderLabelTextScale = res.getFloat(R.dimen.folder_label_text_scale); folderContentPaddingLeftRight = diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index b6a2459c2c..cdc313f351 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -89,15 +89,15 @@ public class AllAppsTransitionController private float mShiftRange; // changes depending on the orientation private float mProgress; // [0, 1], mShiftRange * mProgress = shiftCurrent - private float mScrollRangeDelta = 0; private ScrimView mScrimView; public AllAppsTransitionController(Launcher l) { mLauncher = l; - mShiftRange = mLauncher.getDeviceProfile().heightPx; + DeviceProfile dp = mLauncher.getDeviceProfile(); + setShiftRange(dp.allAppsShiftRange); mProgress = 1f; - mIsVerticalLayout = mLauncher.getDeviceProfile().isVerticalBarLayout(); + mIsVerticalLayout = dp.isVerticalBarLayout(); mLauncher.addOnDeviceProfileChangeListener(this); } @@ -108,7 +108,7 @@ public class AllAppsTransitionController @Override public void onDeviceProfileChanged(DeviceProfile dp) { mIsVerticalLayout = dp.isVerticalBarLayout(); - setScrollRangeDelta(mScrollRangeDelta); + setShiftRange(dp.allAppsShiftRange); if (mIsVerticalLayout) { mLauncher.getHotseat().setTranslationY(0); @@ -160,12 +160,14 @@ public class AllAppsTransitionController } // need to decide depending on the release velocity - Interpolator interpolator = (config.userControlled ? LINEAR : DEACCEL_1_7); - + Interpolator verticalProgressInterpolator = config.getInterpolator(ANIM_VERTICAL_PROGRESS, + config.userControlled ? LINEAR : DEACCEL_1_7); Animator anim = createSpringAnimation(mProgress, targetProgress); - anim.setInterpolator(config.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator)); + anim.setInterpolator(verticalProgressInterpolator); anim.addListener(getProgressAnimatorListener()); builder.add(anim); + // Use ANIM_VERTICAL_PROGRESS's interpolator to determine state transition threshold. + builder.setInterpolator(verticalProgressInterpolator); setAlphas(toState, config, builder); @@ -215,9 +217,8 @@ public class AllAppsTransitionController /** * Updates the total scroll range but does not update the UI. */ - public void setScrollRangeDelta(float delta) { - mScrollRangeDelta = delta; - mShiftRange = mLauncher.getDeviceProfile().heightPx - mScrollRangeDelta; + public void setShiftRange(float shiftRange) { + mShiftRange = shiftRange; } /** diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java index 59e21c099c..bfc75153a5 100644 --- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java @@ -408,7 +408,7 @@ public abstract class BaseAllAppsContainerView { + float startTeleport = 0.2f; + float endTeleport = 0.4f; + float teleportProgress = 0.5f; + float v; + if (t < startTeleport) { + v = LINEAR.getInterpolation(t); + } else if (t < endTeleport) { + v = Utilities.mapToRange(t, startTeleport, endTeleport, startTeleport, + endTeleport + teleportProgress, ACCEL_DEACCEL); + } else { + v = LINEAR.getInterpolation(t) + teleportProgress; + } + v = Utilities.boundToRange(v, 0f, 1f); + return v; + }; + private static final float FAST_FLING_PX_MS = 10; public static Interpolator scrollInterpolatorForVelocity(float velocity) { diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java index 3ab893b0a1..1300ce7f9c 100644 --- a/src/com/android/launcher3/anim/PendingAnimation.java +++ b/src/com/android/launcher3/anim/PendingAnimation.java @@ -77,6 +77,13 @@ public class PendingAnimation implements PropertySetter { addAnimationHoldersRecur(a, mDuration, springProperty, mAnimHolders); } + /** + * Configures interpolator of the underlying AnimatorSet. + */ + public void setInterpolator(TimeInterpolator interpolator) { + mAnim.setInterpolator(interpolator); + } + @Override public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) { if (view == null || view.getAlpha() == alpha) { diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java index 989a9e4c24..f7d34921d3 100644 --- a/src/com/android/launcher3/touch/AllAppsSwipeController.java +++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java @@ -17,9 +17,13 @@ package com.android.launcher3.touch; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; +import static com.android.launcher3.anim.Interpolators.FINAL_FRAME; +import static com.android.launcher3.anim.Interpolators.INSTANT; import static com.android.launcher3.anim.Interpolators.LINEAR; +import static com.android.launcher3.anim.Interpolators.LINEAR_TELEPORT; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS; import android.view.MotionEvent; import android.view.animation.Interpolator; @@ -94,9 +98,9 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController { LauncherState toState) { StateAnimationConfig config = super.getConfigForStates(fromState, toState); if (fromState == NORMAL && toState == ALL_APPS) { - applyNormalToAllAppsAnimConfig(config); + applyNormalToAllAppsAnimConfig(mLauncher, config); } else if (fromState == ALL_APPS && toState == NORMAL) { - applyAllAppsToNormalConfig(config); + applyAllAppsToNormalConfig(mLauncher, config); } return config; } @@ -104,17 +108,24 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController { /** * Applies Animation config values for transition from all apps to home */ - public static void applyAllAppsToNormalConfig(StateAnimationConfig config) { + public static void applyAllAppsToNormalConfig(Launcher launcher, StateAnimationConfig config) { + boolean isTablet = launcher.getDeviceProfile().isTablet; config.setInterpolator(ANIM_SCRIM_FADE, ALLAPPS_STAGGERED_FADE_LATE_RESPONDER); - config.setInterpolator(ANIM_ALL_APPS_FADE, ALLAPPS_STAGGERED_FADE_EARLY_RESPONDER); + config.setInterpolator(ANIM_ALL_APPS_FADE, isTablet + ? FINAL_FRAME : ALLAPPS_STAGGERED_FADE_EARLY_RESPONDER); + config.setInterpolator(ANIM_VERTICAL_PROGRESS, isTablet ? LINEAR_TELEPORT : LINEAR); } /** * Applies Animation config values for transition from home to all apps */ - public static void applyNormalToAllAppsAnimConfig(StateAnimationConfig config) { + public static void applyNormalToAllAppsAnimConfig(Launcher launcher, + StateAnimationConfig config) { + boolean isTablet = launcher.getDeviceProfile().isTablet; config.setInterpolator(ANIM_SCRIM_FADE, ALLAPPS_STAGGERED_FADE_EARLY_RESPONDER); - config.setInterpolator(ANIM_ALL_APPS_FADE, ALLAPPS_STAGGERED_FADE_LATE_RESPONDER); + config.setInterpolator(ANIM_ALL_APPS_FADE, isTablet + ? INSTANT : ALLAPPS_STAGGERED_FADE_LATE_RESPONDER); + config.setInterpolator(ANIM_VERTICAL_PROGRESS, isTablet ? LINEAR_TELEPORT : LINEAR); } diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java index c22d60d0a9..5d888846a8 100644 --- a/src/com/android/launcher3/views/AbstractSlideInView.java +++ b/src/com/android/launcher3/views/AbstractSlideInView.java @@ -113,9 +113,16 @@ public abstract class AbstractSlideInView return -1; } + /** + * Returns the range in height that the slide in view can be dragged. + */ + protected float getShiftRange() { + return mContent.getHeight(); + } + protected void setTranslationShift(float translationShift) { mTranslationShift = translationShift; - mContent.setTranslationY(mTranslationShift * mContent.getHeight()); + mContent.setTranslationY(mTranslationShift * getShiftRange()); if (mColorScrim != null) { mColorScrim.setAlpha(1 - mTranslationShift); } @@ -132,8 +139,7 @@ public abstract class AbstractSlideInView mSwipeDetector.setDetectableScrollConditions( directionsToDetectScroll, false); mSwipeDetector.onTouchEvent(ev); - return mSwipeDetector.isDraggingOrSettling() - || !getPopupContainer().isEventOverView(mContent, ev); + return mSwipeDetector.isDraggingOrSettling() || !isEventOverContent(ev); } @Override @@ -142,13 +148,23 @@ public abstract class AbstractSlideInView if (ev.getAction() == MotionEvent.ACTION_UP && mSwipeDetector.isIdleState() && !isOpeningAnimationRunning()) { // If we got ACTION_UP without ever starting swipe, close the panel. - if (!getPopupContainer().isEventOverView(mContent, ev)) { + if (!isEventOverContent(ev)) { close(true); } } return true; } + /** + * Returns {@code true} if the touch event is over the visible area of the bottom sheet. + * + * By default will check if the touch event is over {@code mContent}, subclasses should override + * this method if the visible area of the bottom sheet is different from {@code mContent}. + */ + protected boolean isEventOverContent(MotionEvent ev) { + return getPopupContainer().isEventOverView(mContent, ev); + } + private boolean isOpeningAnimationRunning() { return mIsOpen && mOpenCloseAnimator.isRunning(); } @@ -160,7 +176,7 @@ public abstract class AbstractSlideInView @Override public boolean onDrag(float displacement) { - float range = mContent.getHeight(); + float range = getShiftRange(); displacement = Utilities.boundToRange(displacement, 0, range); setTranslationShift(displacement / range); return true; diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java index 5543cc2696..8a435c9647 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java @@ -55,8 +55,15 @@ public class AllAppsState extends LauncherState { @Override public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) { - return new ScaleAndTranslation(1f, 0, - -launcher.getAllAppsController().getShiftRange() * PARALLAX_COEFFICIENT); + ScaleAndTranslation scaleAndTranslation = + new ScaleAndTranslation(NO_SCALE, NO_OFFSET, NO_OFFSET); + if (launcher.getDeviceProfile().isTablet) { + scaleAndTranslation.scale = 0.97f; + } else { + scaleAndTranslation.translationY = + -launcher.getAllAppsController().getShiftRange() * PARALLAX_COEFFICIENT; + } + return scaleAndTranslation; } @Override