diff --git a/go/AndroidManifest.xml b/go/AndroidManifest.xml index f36439db53..2671604f94 100644 --- a/go/AndroidManifest.xml +++ b/go/AndroidManifest.xml @@ -24,6 +24,8 @@ + + The type of View in which the overlay will be placed */ public static final class TaskOverlayGo extends TaskOverlay { + private static final String ASSIST_KEY_CONTENT = "content"; - private String mPackageName; + private String mNIUPackageName; + private int mTaskId; + private Bundle mAssistData; + private final Handler mMainThreadHandler; private TaskOverlayGo(TaskThumbnailView taskThumbnailView) { super(taskThumbnailView); + mMainThreadHandler = new Handler(Looper.getMainLooper()); } /** @@ -70,16 +87,39 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix, boolean rotated) { getActionsView().updateDisabledFlags(DISABLED_NO_THUMBNAIL, thumbnail == null); - mPackageName = + mNIUPackageName = mApplicationContext.getResources().getString(R.string.niu_actions_package); - if (thumbnail == null || TextUtils.isEmpty(mPackageName)) { + if (thumbnail == null || TextUtils.isEmpty(mNIUPackageName)) { return; } getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated); boolean isAllowedByPolicy = thumbnail.isRealSnapshot; getActionsView().setCallbacks(new OverlayUICallbacksGoImpl(isAllowedByPolicy, task)); + + mTaskId = task.key.id; + AssistDataReceiverImpl receiver = new AssistDataReceiverImpl(); + receiver.setOverlay(this); + + try { + ActivityTaskManager.getService().requestAssistDataForTask(receiver, mTaskId, + mApplicationContext.getPackageName()); + } catch (RemoteException e) { + Log.e(TAG, "Unable to request AssistData"); + } + } + + /** + * Called when AssistDataReceiverImpl receives data from ActivityTaskManagerService's + * AssistDataRequester + */ + public void onAssistDataReceived(Bundle data) { + mMainThreadHandler.post(() -> { + if (data != null) { + mAssistData = data; + } + }); } private void sendNIUIntent(String actionType) { @@ -88,11 +128,21 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { } private Intent createNIUIntent(String actionType) { - return new Intent(actionType) + Intent intent = new Intent(actionType) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) - .setPackage(mPackageName) + .setPackage(mNIUPackageName) .putExtra(ELAPSED_NANOS, SystemClock.elapsedRealtimeNanos()); + + if (mAssistData != null) { + final AssistContent content = mAssistData.getParcelable(ASSIST_KEY_CONTENT); + Uri webUri = (content == null) ? null : content.getWebUri(); + if (webUri != null) { + intent.putExtra(ACTIONS_URL, webUri.toString()); + } + } + + return intent; } protected class OverlayUICallbacksGoImpl extends OverlayUICallbacksImpl @@ -130,6 +180,26 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { } } + /** + * Basic AssistDataReceiver. This is passed to ActivityTaskManagerService, which then requests + * the data. + */ + private static final class AssistDataReceiverImpl extends IAssistDataReceiver.Stub { + private TaskOverlayGo mOverlay; + + public void setOverlay(TaskOverlayGo overlay) { + mOverlay = overlay; + } + + @Override + public void onHandleAssistData(Bundle data) { + mOverlay.onAssistDataReceived(data); + } + + @Override + public void onHandleAssistScreenshot(Bitmap screenshot) {} + } + /** * Callbacks the Ui can generate. This is the only way for a Ui to call methods on the * controller. diff --git a/quickstep/res/layout/taskbar_divider.xml b/quickstep/res/layout/taskbar_divider.xml index 6e1aa1e3d5..87649f752e 100644 --- a/quickstep/res/layout/taskbar_divider.xml +++ b/quickstep/res/layout/taskbar_divider.xml @@ -18,6 +18,4 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="@dimen/taskbar_divider_thickness" android:layout_height="@dimen/taskbar_divider_height" - android:layout_marginStart="@dimen/taskbar_icon_spacing" - android:layout_marginEnd="@dimen/taskbar_icon_spacing" android:background="@color/taskbar_divider" /> \ No newline at end of file diff --git a/quickstep/res/layout/taskbar_view.xml b/quickstep/res/layout/taskbar_view.xml new file mode 100644 index 0000000000..34a88ea6a2 --- /dev/null +++ b/quickstep/res/layout/taskbar_view.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index c4becf105f..9ab49cebfa 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -46,6 +46,7 @@ import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarController; 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; @@ -243,9 +244,10 @@ public abstract class BaseQuickstepLauncher extends Launcher mTaskbarController = null; } if (mDeviceProfile.isTaskbarPresent) { + TaskbarView taskbarViewOnHome = (TaskbarView) mHotseat.getTaskbarView(); TaskbarActivityContext taskbarActivityContext = new TaskbarActivityContext(this); mTaskbarController = new TaskbarController(this, - taskbarActivityContext.getTaskbarContainerView()); + taskbarActivityContext.getTaskbarContainerView(), taskbarViewOnHome); mTaskbarController.init(); } } diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java index b1b4d70152..df3657d01d 100644 --- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java +++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java @@ -73,6 +73,7 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state"; private static final String LAST_SNAPSHOT_TIME_MILLIS = "LAST_SNAPSHOT_TIME_MILLIS"; + private static final int NUM_OF_RECOMMENDED_WIDGETS_PREDICATION = 20; private static final boolean IS_DEBUG = false; private static final String TAG = "QuickstepModelDelegate"; @@ -217,7 +218,7 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange registerWidgetsPredictor(apm.createAppPredictionSession( new AppPredictionContext.Builder(context) .setUiSurface("widgets") - .setPredictedTargetCount(mIDP.numColumns) + .setPredictedTargetCount(NUM_OF_RECOMMENDED_WIDGETS_PREDICATION) .build())); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 8312b82062..fc5e2c1740 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -54,10 +54,7 @@ public class TaskbarActivityContext extends ContextWrapper implements ActivityCo return mTaskbarContainerView; } - /** - * @return A LayoutInflater to use in this Context. Views inflated with this LayoutInflater will - * be able to access this TaskbarActivityContext via ActivityContext.lookupContext(). - */ + @Override public LayoutInflater getLayoutInflater() { return mLayoutInflater; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java index 528f43e699..5202d91684 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java @@ -84,7 +84,7 @@ public class TaskbarContainerView extends BaseDragLayer private ViewTreeObserverWrapper.OnComputeInsetsListener createTaskbarInsetsComputer() { return insetsInfo -> { if (getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD - || mTaskbarView.isDraggingItem()) { + || mTaskbarView.getVisibility() != VISIBLE || mTaskbarView.isDraggingItem()) { // We're invisible or dragging out of taskbar, let touches pass through us. insetsInfo.touchableRegion.setEmpty(); insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java index f652961629..abf6d54146 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java @@ -19,8 +19,6 @@ 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.launcher3.AbstractFloatingView.TYPE_HIDE_TASKBAR; -import static com.android.launcher3.AbstractFloatingView.TYPE_REPLACE_TASKBAR_WITH_HOTSEAT; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT; @@ -43,7 +41,6 @@ import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.Hotseat; import com.android.launcher3.LauncherState; import com.android.launcher3.QuickstepTransitionManager; import com.android.launcher3.R; @@ -54,6 +51,7 @@ import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.ItemClickHandler; +import com.android.launcher3.views.ActivityContext; import com.android.quickstep.AnimatedFloat; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -70,7 +68,8 @@ public class TaskbarController { private static final String WINDOW_TITLE = "Taskbar"; private final TaskbarContainerView mTaskbarContainerView; - private final TaskbarView mTaskbarView; + private final TaskbarView mTaskbarViewInApp; + private final TaskbarView mTaskbarViewOnHome; private final BaseQuickstepLauncher mLauncher; private final WindowManager mWindowManager; // Layout width and height of the Taskbar in the default state. @@ -91,14 +90,17 @@ public class TaskbarController { private @Nullable Animator mAnimator; private boolean mIsAnimatingToLauncher; + private boolean mIsAnimatingToApp; public TaskbarController(BaseQuickstepLauncher launcher, - TaskbarContainerView taskbarContainerView) { + TaskbarContainerView taskbarContainerView, TaskbarView taskbarViewOnHome) { mLauncher = launcher; mTaskbarContainerView = taskbarContainerView; mTaskbarContainerView.construct(createTaskbarContainerViewCallbacks()); - mTaskbarView = mTaskbarContainerView.findViewById(R.id.taskbar_view); - mTaskbarView.construct(createTaskbarViewCallbacks()); + mTaskbarViewInApp = mTaskbarContainerView.findViewById(R.id.taskbar_view); + mTaskbarViewInApp.construct(createTaskbarViewCallbacks()); + mTaskbarViewOnHome = taskbarViewOnHome; + mTaskbarViewOnHome.construct(createTaskbarViewCallbacks()); mWindowManager = mLauncher.getWindowManager(); mTaskbarSize = new Point(MATCH_PARENT, mLauncher.getDeviceProfile().taskbarSize); mTaskbarStateHandler = mLauncher.getTaskbarStateHandler(); @@ -115,12 +117,13 @@ public class TaskbarController { return new TaskbarVisibilityControllerCallbacks() { @Override public void updateTaskbarBackgroundAlpha(float alpha) { - mTaskbarView.setBackgroundAlpha(alpha); + mTaskbarViewInApp.setBackgroundAlpha(alpha); } @Override public void updateTaskbarVisibilityAlpha(float alpha) { mTaskbarContainerView.setAlpha(alpha); + mTaskbarViewOnHome.setAlpha(alpha); } }; } @@ -196,7 +199,7 @@ public class TaskbarController { public View.OnLongClickListener getItemOnLongClickListener() { return view -> { if (mLauncher.hasBeenResumed() && view.getTag() instanceof ItemInfo) { - alignRealHotseatWithTaskbar(); + // TODO: remove this path return mDragController.startWorkspaceDragOnLongClick(view); } else { return mDragController.startSystemDragOnLongClick(view); @@ -205,11 +208,24 @@ public class TaskbarController { } @Override - public int getEmptyHotseatViewVisibility() { + 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. - return mLauncher.hasBeenResumed() || mIsAnimatingToLauncher - ? View.INVISIBLE : View.GONE; + boolean isOnHomeScreen = taskbarView == mTaskbarViewOnHome + || mLauncher.hasBeenResumed() || mIsAnimatingToLauncher; + return isOnHomeScreen ? View.INVISIBLE : View.GONE; + } + + @Override + public float getNonIconScale(TaskbarView taskbarView) { + return taskbarView == mTaskbarViewOnHome ? getTaskbarScaleOnHome() : 1f; + } + + @Override + public void onItemPositionsChanged(TaskbarView taskbarView) { + if (taskbarView == mTaskbarViewOnHome) { + alignRealHotseatWithTaskbar(); + } } }; } @@ -218,7 +234,7 @@ public class TaskbarController { return new TaskbarHotseatControllerCallbacks() { @Override public void updateHotseatItems(ItemInfo[] hotseatItemInfos) { - mTaskbarView.updateHotseatItems(hotseatItemInfos); + mTaskbarViewInApp.updateHotseatItems(hotseatItemInfos); mLatestLoadedHotseatItems = hotseatItemInfos; dedupeAndUpdateRecentItems(); } @@ -235,7 +251,8 @@ public class TaskbarController { @Override public void updateRecentTaskAtIndex(int taskIndex, Task task) { - mTaskbarView.updateRecentTaskAtIndex(taskIndex, task); + mTaskbarViewInApp.updateRecentTaskAtIndex(taskIndex, task); + mTaskbarViewOnHome.updateRecentTaskAtIndex(taskIndex, task); } }; } @@ -244,16 +261,20 @@ public class TaskbarController { * Initializes the Taskbar, including adding it to the screen. */ public void init() { - mTaskbarView.init(mHotseatController.getNumHotseatIcons(), + mTaskbarViewInApp.init(mHotseatController.getNumHotseatIcons(), mRecentsController.getNumRecentIcons()); - mTaskbarContainerView.init(mTaskbarView); + mTaskbarViewOnHome.init(mHotseatController.getNumHotseatIcons(), + mRecentsController.getNumRecentIcons()); + mTaskbarContainerView.init(mTaskbarViewInApp); addToWindowManager(); mTaskbarStateHandler.setTaskbarCallbacks(createTaskbarStateHandlerCallbacks()); mTaskbarVisibilityController.init(); mHotseatController.init(); mRecentsController.init(); - SCALE_PROPERTY.set(mTaskbarView, mLauncher.hasBeenResumed() ? getTaskbarScaleOnHome() : 1f); + SCALE_PROPERTY.set(mTaskbarViewInApp, mLauncher.hasBeenResumed() + ? getTaskbarScaleOnHome() : 1f); + updateWhichTaskbarViewIsVisible(); } private TaskbarStateHandlerCallbacks createTaskbarStateHandlerCallbacks() { @@ -274,7 +295,8 @@ public class TaskbarController { mAnimator.end(); } - mTaskbarView.cleanup(); + mTaskbarViewInApp.cleanup(); + mTaskbarViewOnHome.cleanup(); mTaskbarContainerView.cleanup(); removeFromWindowManager(); mTaskbarStateHandler.setTaskbarCallbacks(null); @@ -313,7 +335,7 @@ public class TaskbarController { TaskbarContainerView.LayoutParams taskbarLayoutParams = new TaskbarContainerView.LayoutParams(mTaskbarSize.x, mTaskbarSize.y); taskbarLayoutParams.gravity = gravity; - mTaskbarView.setLayoutParams(taskbarLayoutParams); + mTaskbarViewInApp.setLayoutParams(taskbarLayoutParams); mWindowManager.addView(mTaskbarContainerView, mWindowLayoutParams); } @@ -330,7 +352,6 @@ public class TaskbarController { mAnimator = createAnimToLauncher(null, duration); } else { mAnimator = createAnimToApp(duration); - replaceTaskbarWithHotseatOrViceVersa(); } mAnimator.addListener(new AnimatorListenerAdapter() { @Override @@ -351,36 +372,41 @@ public class TaskbarController { if (toState != null) { mTaskbarStateHandler.setStateWithAnimation(toState, new StateAnimationConfig(), anim); } - anim.addFloat(mTaskbarView, SCALE_PROPERTY, mTaskbarView.getScaleX(), + anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(), getTaskbarScaleOnHome(), LINEAR); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { mIsAnimatingToLauncher = true; - mTaskbarView.updateHotseatItemsVisibility(); + mTaskbarViewInApp.updateHotseatItemsVisibility(); } @Override public void onAnimationEnd(Animator animation) { mIsAnimatingToLauncher = false; + updateWhichTaskbarViewIsVisible(); } }); - anim.addOnFrameCallback(this::alignRealHotseatWithTaskbar); - return anim.buildAnim(); } private Animator createAnimToApp(long duration) { PendingAnimation anim = new PendingAnimation(duration); anim.add(mTaskbarVisibilityController.createAnimToBackgroundAlpha(1, duration)); - anim.addFloat(mTaskbarView, SCALE_PROPERTY, mTaskbarView.getScaleX(), 1f, LINEAR); + anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(), 1f, LINEAR); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { - mTaskbarView.updateHotseatItemsVisibility(); - setReplaceTaskbarWithHotseat(false); + mIsAnimatingToApp = true; + mTaskbarViewInApp.updateHotseatItemsVisibility(); + updateWhichTaskbarViewIsVisible(); + } + + @Override + public void onAnimationEnd(Animator animation) { + mIsAnimatingToApp = false; } }); return anim.buildAnim(); @@ -405,11 +431,11 @@ public class TaskbarController { * @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(); } private void dedupeAndUpdateRecentItems() { @@ -454,7 +480,8 @@ public class TaskbarController { tasksArray[tasksArray.length - 1 - i] = task; } - mTaskbarView.updateRecentTasks(tasksArray); + mTaskbarViewInApp.updateRecentTasks(tasksArray); + mTaskbarViewOnHome.updateRecentTasks(tasksArray); mRecentsController.loadIconsForTasks(tasksArray); } @@ -475,10 +502,11 @@ public class TaskbarController { int hotseatHeight = grid.workspacePadding.bottom + grid.taskbarSize; int hotseatTopDiff = hotseatHeight - grid.taskbarSize; - mTaskbarView.getHotseatBoundsAtScale(getTaskbarScaleOnHome()).roundOut(hotseatBounds); - mLauncher.getHotseat().setPadding(hotseatBounds.left, hotseatBounds.top + hotseatTopDiff, - mTaskbarView.getWidth() - hotseatBounds.right, - mTaskbarView.getHeight() - hotseatBounds.bottom); + mTaskbarViewOnHome.getHotseatBounds().roundOut(hotseatBounds); + mLauncher.getHotseat().setPadding(hotseatBounds.left, + hotseatBounds.top + hotseatTopDiff, + mTaskbarViewOnHome.getWidth() - hotseatBounds.right, + mTaskbarViewOnHome.getHeight() - hotseatBounds.bottom); } /** @@ -486,36 +514,32 @@ public class TaskbarController { * show the real one instead. */ public void onLauncherDragLayerHierarchyChanged() { - replaceTaskbarWithHotseatOrViceVersa(); + // TODO: remove, as this is a no-op now } - private void replaceTaskbarWithHotseatOrViceVersa() { - boolean replaceTaskbarWithHotseat = AbstractFloatingView.getTopOpenViewWithType(mLauncher, - TYPE_REPLACE_TASKBAR_WITH_HOTSEAT) != null; - if (!mLauncher.hasBeenResumed()) { - replaceTaskbarWithHotseat = false; - } - setReplaceTaskbarWithHotseat(replaceTaskbarWithHotseat); - - boolean hideTaskbar = AbstractFloatingView.getTopOpenViewWithType(mLauncher, - TYPE_HIDE_TASKBAR) != null; - mTaskbarVisibilityController.animateToVisibilityForFloatingView(hideTaskbar ? 0f : 1f); - } - - private void setReplaceTaskbarWithHotseat(boolean replaceTaskbarWithHotseat) { - Hotseat hotseat = mLauncher.getHotseat(); - if (replaceTaskbarWithHotseat) { - alignRealHotseatWithTaskbar(); - hotseat.getReplaceTaskbarAlpha().setValue(1f); - mTaskbarView.setHotseatViewsHidden(true); + private void updateWhichTaskbarViewIsVisible() { + boolean isInApp = !mLauncher.hasBeenResumed() || mIsAnimatingToLauncher + || mIsAnimatingToApp; + if (isInApp) { + mTaskbarViewInApp.setVisibility(View.VISIBLE); + mTaskbarViewOnHome.setVisibility(View.INVISIBLE); + mLauncher.getHotseat().setIconsAlpha(0); } else { - hotseat.getReplaceTaskbarAlpha().setValue(0f); - mTaskbarView.setHotseatViewsHidden(false); + mTaskbarViewInApp.setVisibility(View.INVISIBLE); + mTaskbarViewOnHome.setVisibility(View.VISIBLE); + mLauncher.getHotseat().setIconsAlpha(1); } } - private float getTaskbarScaleOnHome() { - return 1f / mTaskbarContainerView.getTaskbarActivityContext().getTaskbarIconScale(); + /** + * Returns the ratio of the taskbar icon size on home vs in an app. + */ + public float getTaskbarScaleOnHome() { + DeviceProfile inAppDp = mTaskbarContainerView.getTaskbarActivityContext() + .getDeviceProfile(); + DeviceProfile onHomeDp = ActivityContext.lookupContext(mTaskbarViewOnHome.getContext()) + .getDeviceProfile(); + return (float) onHomeDp.cellWidthPx / inAppDp.cellWidthPx; } /** @@ -561,7 +585,10 @@ public class TaskbarController { protected interface TaskbarViewCallbacks { View.OnClickListener getItemOnClickListener(); View.OnLongClickListener getItemOnLongClickListener(); - int getEmptyHotseatViewVisibility(); + 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); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index 1d762e9696..3567c17afa 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -15,11 +15,14 @@ */ package com.android.launcher3.taskbar; +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.Matrix; +import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; @@ -36,6 +39,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BubbleTextView; +import com.android.launcher3.Insettable; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.folder.FolderIcon; @@ -48,20 +52,23 @@ import com.android.systemui.shared.recents.model.Task; /** * Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps. */ -public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconParent { +public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconParent, Insettable { private final ColorDrawable mBackgroundDrawable; - private final int mItemMarginLeftRight; + private final int mDividerWidth; + private final int mDividerHeight; private final int mIconTouchSize; private final boolean mIsRtl; private final int mTouchSlop; private final RectF mTempDelegateBounds = new RectF(); private final RectF mDelegateSlopBounds = new RectF(); private final int[] mTempOutLocation = new int[2]; - private final Matrix mTempMatrix = new Matrix(); // Initialized in TaskbarController constructor. private TaskbarController.TaskbarViewCallbacks mControllerCallbacks; + // Scale on elements that aren't icons. + private float mNonIconScale; + private int mItemMarginLeftRight; // Initialized in init(). private LayoutTransition mLayoutTransition; @@ -78,7 +85,6 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa private boolean mIsDraggingItem; // Only non-null when the corresponding Folder is open. private @Nullable FolderIcon mLeaveBehindFolderIcon; - private boolean mIsHotseatHidden; public TaskbarView(@NonNull Context context) { this(context, null); @@ -99,7 +105,8 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa Resources resources = getResources(); mBackgroundDrawable = (ColorDrawable) getBackground(); - mItemMarginLeftRight = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing); + mDividerWidth = resources.getDimensionPixelSize(R.dimen.taskbar_divider_thickness); + mDividerHeight = resources.getDimensionPixelSize(R.dimen.taskbar_divider_height); mIconTouchSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_touch_size); mIsRtl = Utilities.isRtl(resources); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); @@ -107,11 +114,16 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa protected void construct(TaskbarController.TaskbarViewCallbacks taskbarViewCallbacks) { mControllerCallbacks = taskbarViewCallbacks; + mNonIconScale = mControllerCallbacks.getNonIconScale(this); + mItemMarginLeftRight = getResources().getDimensionPixelSize(R.dimen.taskbar_icon_spacing); + mItemMarginLeftRight = Math.round(mItemMarginLeftRight * mNonIconScale); } protected void init(int numHotseatIcons, int numRecentIcons) { mLayoutTransition = new LayoutTransition(); - setLayoutTransitionsEnabled(true); + addUpdateListenerForAllLayoutTransitions( + () -> mControllerCallbacks.onItemPositionsChanged(this)); + setLayoutTransition(mLayoutTransition); mHotseatStartIndex = 0; mHotseatEndIndex = mHotseatStartIndex + numHotseatIcons - 1; @@ -125,12 +137,30 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa updateRecentTasks(new Task[numRecentIcons]); } - private void setLayoutTransitionsEnabled(boolean enabled) { - setLayoutTransition(enabled ? mLayoutTransition : null); + 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); + } } protected void cleanup() { removeAllViews(); + mHotseatRecentsDivider = null; } /** @@ -170,12 +200,11 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa if (hotseatView == null || hotseatView.getSourceLayoutResId() != expectedLayoutResId || needsReinflate) { removeView(hotseatView); - TaskbarActivityContext activityContext = - ActivityContext.lookupContext(getContext()); + ActivityContext activityContext = ActivityContext.lookupContext(getContext()); if (isFolder) { FolderInfo folderInfo = (FolderInfo) hotseatItemInfo; FolderIcon folderIcon = FolderIcon.inflateFolderAndIcon(expectedLayoutResId, - activityContext, this, folderInfo); + ActivityContext.lookupContext(getContext()), this, folderInfo); folderIcon.setTextVisible(false); hotseatView = folderIcon; } else { @@ -216,22 +245,12 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } } - /** - * Hides or shows the hotseat items immediately (without layout transitions). - */ - protected void setHotseatViewsHidden(boolean hidden) { - mIsHotseatHidden = hidden; - setLayoutTransitionsEnabled(false); - updateHotseatItemsVisibility(); - setLayoutTransitionsEnabled(true); - } - private void updateHotseatItemVisibility(View hotseatView) { if (hotseatView.getTag() != null) { - hotseatView.setVisibility(mIsHotseatHidden ? INVISIBLE : VISIBLE); + hotseatView.setVisibility(VISIBLE); } else { int oldVisibility = hotseatView.getVisibility(); - int newVisibility = mControllerCallbacks.getEmptyHotseatViewVisibility(); + int newVisibility = mControllerCallbacks.getEmptyHotseatViewVisibility(this); hotseatView.setVisibility(newVisibility); if (oldVisibility == GONE && newVisibility != GONE) { // By default, the layout transition only runs when going to VISIBLE, @@ -243,7 +262,11 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa private View addDivider(int dividerIndex) { View divider = inflate(R.layout.taskbar_divider); - addView(divider, dividerIndex); + LayoutParams lp = new LayoutParams(mDividerWidth, mDividerHeight); + lp.setMargins(mItemMarginLeftRight, 0, mItemMarginLeftRight, 0); + divider.setScaleX(mNonIconScale); + divider.setScaleY(mNonIconScale); + addView(divider, dividerIndex, lp); return divider; } @@ -437,9 +460,9 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } /** - * @return The bounding box of where the hotseat elements will be when we reach the given scale. + * @return The bounding box of where the hotseat elements are relative to this TaskbarView. */ - protected RectF getHotseatBoundsAtScale(float taskbarViewScale) { + protected RectF getHotseatBounds() { View firstHotseatView = null, lastHotseatView = null; for (int i = mHotseatStartIndex; i <= mHotseatEndIndex; i++) { View child = getChildAt(i); @@ -455,14 +478,11 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } View leftmostHotseatView = !mIsRtl ? firstHotseatView : lastHotseatView; View rightmostHotseatView = !mIsRtl ? lastHotseatView : firstHotseatView; - RectF hotseatBounds = new RectF( + return new RectF( leftmostHotseatView.getLeft() - mItemMarginLeftRight, leftmostHotseatView.getTop(), rightmostHotseatView.getRight() + mItemMarginLeftRight, rightmostHotseatView.getBottom()); - mTempMatrix.setScale(taskbarViewScale, taskbarViewScale, getPivotX(), getPivotY()); - mTempMatrix.mapRect(hotseatBounds); - return hotseatBounds; } // FolderIconParent implemented methods. @@ -493,7 +513,12 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } private View inflate(@LayoutRes int layoutResId) { - TaskbarActivityContext taskbarActivityContext = ActivityContext.lookupContext(getContext()); - return taskbarActivityContext.getLayoutInflater().inflate(layoutResId, this, false); + return ActivityContext.lookupContext(getContext()).getLayoutInflater() + .inflate(layoutResId, this, false); + } + + @Override + public void setInsets(Rect insets) { + // Ignore, we just implement Insettable to draw behind system insets. } } diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 30945007a9..b49282544d 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -617,7 +617,7 @@ public abstract class AbsSwipeUpHandler, final boolean passed = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW; if (passed != mPassedOverviewThreshold) { mPassedOverviewThreshold = passed; - if (!mDeviceState.isTwoButtonNavMode()) { + if (mDeviceState.isTwoButtonNavMode()) { performHapticFeedback(); } } diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java index ae644cd6fd..3faf72a006 100644 --- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java +++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java @@ -112,20 +112,32 @@ public class StaggeredWorkspaceAnim { } // Set up springs for the hotseat and qsb. - ViewGroup hotseatChild = (ViewGroup) hotseat.getChildAt(0); + ViewGroup hotseatIcons = hotseat.getShortcutsAndWidgets(); if (grid.isVerticalBarLayout()) { - for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) { - View child = hotseatChild.getChildAt(i); + for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) { + View child = hotseatIcons.getChildAt(i); CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams()); addStaggeredAnimationForView(child, lp.cellY + 1, totalRows); } } else { - for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) { - View child = hotseatChild.getChildAt(i); - addStaggeredAnimationForView(child, grid.inv.numRows + 1, totalRows); + final int hotseatRow, qsbRow, taskbarRow; + if (grid.isTaskbarPresent) { + qsbRow = grid.inv.numRows + 1; + hotseatRow = grid.inv.numRows + 2; + } else { + hotseatRow = grid.inv.numRows + 1; + qsbRow = grid.inv.numRows + 2; + } + // Taskbar and hotseat overlap. + taskbarRow = hotseatRow; + + for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) { + View child = hotseatIcons.getChildAt(i); + addStaggeredAnimationForView(child, hotseatRow, totalRows); } - addStaggeredAnimationForView(hotseat.getQsb(), grid.inv.numRows + 2, totalRows); + addStaggeredAnimationForView(hotseat.getQsb(), qsbRow, totalRows); + addStaggeredAnimationForView(hotseat.getTaskbarView(), taskbarRow, totalRows); } if (animateOverviewScrim) { diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 809adcbe21..2b7e6fd059 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -298,7 +298,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { private boolean mEndQuickswitchCuj; private View mContextualChipWrapper; - private View mContextualChip; private final float[] mIconCenterCoords = new float[2]; private final float[] mChipCenterCoords = new float[2]; @@ -447,9 +446,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } mModalness = modalness; mIconView.setAlpha(comp(modalness)); - if (mContextualChip != null) { - mContextualChip.setScaleX(comp(modalness)); - mContextualChip.setScaleY(comp(modalness)); + if (mContextualChipWrapper != null) { + mContextualChipWrapper.setScaleX(comp(modalness)); + mContextualChipWrapper.setScaleY(comp(modalness)); } mDigitalWellBeingToast.updateBannerOffset(modalness, mCurrentFullscreenParams.mCurrentDrawnInsets.top @@ -689,10 +688,10 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { .getInterpolation(progress); mIconView.setScaleX(scale); mIconView.setScaleY(scale); - if (mContextualChip != null && mContextualChipWrapper != null) { + if (mContextualChipWrapper != null && mContextualChipWrapper != null) { mContextualChipWrapper.setAlpha(scale); - mContextualChip.setScaleX(scale); - mContextualChip.setScaleY(scale); + mContextualChipWrapper.setScaleX(Math.min(scale, comp(mModalness))); + mContextualChipWrapper.setScaleY(Math.min(scale, comp(mModalness))); } mDigitalWellBeingToast.updateBannerOffset(1f - scale, mCurrentFullscreenParams.mCurrentDrawnInsets.top @@ -797,14 +796,12 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { int expectedChipHeight = getExpectedViewHeight(view); float chipOffset = getResources().getDimension(R.dimen.chip_hint_vertical_offset); layoutParams.bottomMargin = -expectedChipHeight - (int) chipOffset; - mContextualChip = ((FrameLayout) mContextualChipWrapper).getChildAt(0); - mContextualChip.setScaleX(0f); - mContextualChip.setScaleY(0f); + mContextualChipWrapper.setScaleX(0f); + mContextualChipWrapper.setScaleY(0f); addView(view, getChildCount(), layoutParams); - if (mContextualChip != null) { - mContextualChip.animate().scaleX(1f).scaleY(1f).setDuration(50); - } if (mContextualChipWrapper != null) { + float scale = comp(mModalness); + mContextualChipWrapper.animate().scaleX(scale).scaleY(scale).setDuration(50); mChipTouchDelegate = new TransformingTouchDelegate(mContextualChipWrapper); } } @@ -825,7 +822,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } View oldContextualChipWrapper = mContextualChipWrapper; mContextualChipWrapper = null; - mContextualChip = null; mChipTouchDelegate = null; return oldContextualChipWrapper; } diff --git a/res/drawable/middle_item_primary.xml b/res/drawable/middle_item_primary.xml index c9757142da..0c04ea14ec 100644 --- a/res/drawable/middle_item_primary.xml +++ b/res/drawable/middle_item_primary.xml @@ -16,5 +16,5 @@ - + \ No newline at end of file diff --git a/res/layout/deep_shortcut.xml b/res/layout/deep_shortcut.xml index d6b4a37dd4..0d11b50ab3 100644 --- a/res/layout/deep_shortcut.xml +++ b/res/layout/deep_shortcut.xml @@ -32,6 +32,8 @@ android:paddingEnd="@dimen/popup_padding_end" android:drawableEnd="@drawable/ic_drag_handle" android:drawablePadding="@dimen/deep_shortcut_drawable_padding" + android:singleLine="true" + android:ellipsize="end" android:textSize="14sp" android:textColor="?android:attr/textColorPrimary" launcher:layoutHorizontal="true" diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml index 68251e4d15..9f45f30216 100644 --- a/res/layout/system_shortcut.xml +++ b/res/layout/system_shortcut.xml @@ -31,7 +31,8 @@ android:paddingStart="@dimen/deep_shortcuts_text_padding_start" android:paddingEnd="@dimen/popup_padding_end" android:textSize="14sp" - android:maxLines="1" + android:singleLine="true" + android:ellipsize="end" android:textColor="?android:attr/textColorPrimary" launcher:iconDisplay="shortcut_popup" launcher:layoutHorizontal="true" diff --git a/res/layout/taskbar_view.xml b/res/layout/taskbar_view.xml new file mode 100644 index 0000000000..96ae43db4a --- /dev/null +++ b/res/layout/taskbar_view.xml @@ -0,0 +1,21 @@ + + + \ No newline at end of file diff --git a/res/layout/widgets_bottom_sheet.xml b/res/layout/widgets_bottom_sheet.xml index d18ba568cf..8002d1ddc7 100644 --- a/res/layout/widgets_bottom_sheet.xml +++ b/res/layout/widgets_bottom_sheet.xml @@ -24,41 +24,7 @@ android:elevation="@dimen/deep_shortcuts_elevation" android:layout_gravity="bottom" android:theme="?attr/widgetsTheme"> - - - - - - - + \ No newline at end of file diff --git a/res/layout/widgets_bottom_sheet_content.xml b/res/layout/widgets_bottom_sheet_content.xml new file mode 100644 index 0000000000..a9d523ae57 --- /dev/null +++ b/res/layout/widgets_bottom_sheet_content.xml @@ -0,0 +1,43 @@ + + + + + + + + + + diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 64c07d03d5..3a07aca226 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -185,7 +185,7 @@ 0dp - 234dp + 216dp 56dp 6dp @@ -193,7 +193,7 @@ 32dp 2dp 100dp - 4dp + 4dp 12dp 16dp 10dp diff --git a/res/values/strings.xml b/res/values/strings.xml index 1eb123bb92..7c37283067 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -269,8 +269,6 @@ %1$s waiting to install - - %1$s widgets Widgets list diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index 8071782617..d02efb0100 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -100,6 +100,8 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O private int mRunningVInc; private int mMinHSpan; private int mMinVSpan; + private int mMaxHSpan; + private int mMaxVSpan; private int mDeltaX; private int mDeltaY; private int mDeltaXAddOn; @@ -183,6 +185,8 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O mMinHSpan = info.minSpanX; mMinVSpan = info.minSpanY; + mMaxHSpan = info.maxSpanX; + mMaxVSpan = info.maxSpanY; mWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(getContext(), widgetView.getAppWidgetInfo().provider, null); @@ -314,7 +318,7 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O // expandability. mTempRange1.set(cellX, spanX + cellX); int hSpanDelta = mTempRange1.applyDeltaAndBound(mLeftBorderActive, mRightBorderActive, - hSpanInc, mMinHSpan, mCellLayout.getCountX(), mTempRange2); + hSpanInc, mMinHSpan, mMaxHSpan, mCellLayout.getCountX(), mTempRange2); cellX = mTempRange2.start; spanX = mTempRange2.size(); if (hSpanDelta != 0) { @@ -323,7 +327,7 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O mTempRange1.set(cellY, spanY + cellY); int vSpanDelta = mTempRange1.applyDeltaAndBound(mTopBorderActive, mBottomBorderActive, - vSpanInc, mMinVSpan, mCellLayout.getCountY(), mTempRange2); + vSpanInc, mMinVSpan, mMaxVSpan, mCellLayout.getCountY(), mTempRange2); cellY = mTempRange2.start; spanY = mTempRange2.size(); if (vSpanDelta != 0) { @@ -642,12 +646,15 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O * @param minSize minimum size after with the moving edge should not be shifted any further. * For eg, if delta = -3 when moving the endEdge brings the size to less than * minSize, only delta = -2 will applied + * @param maxSize maximum size after with the moving edge should not be shifted any further. + * For eg, if delta = -3 when moving the endEdge brings the size to greater + * than maxSize, only delta = -2 will applied * @param maxEnd The maximum value to the end edge (start edge is always restricted to 0) * @return the amount of increase when endEdge was moves and the amount of decrease when * the start edge was moved. */ public int applyDeltaAndBound(boolean moveStart, boolean moveEnd, int delta, - int minSize, int maxEnd, IntRange out) { + int minSize, int maxSize, int maxEnd, IntRange out) { applyDelta(moveStart, moveEnd, delta, out); if (out.start < 0) { out.start = 0; @@ -662,6 +669,13 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O out.end = out.start + minSize; } } + if (out.size() > maxSize) { + if (moveStart) { + out.start = out.end - maxSize; + } else if (moveEnd) { + out.end = out.start + maxSize; + } + } return moveEnd ? out.size() - size() : size() - out.size(); } } diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index af4a843b12..4049ed6882 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -29,8 +29,6 @@ import android.widget.FrameLayout; import androidx.annotation.Nullable; -import com.android.launcher3.util.MultiValueAlpha; - import java.util.function.Consumer; /** @@ -38,10 +36,6 @@ import java.util.function.Consumer; */ public class Hotseat extends CellLayout implements Insettable { - private static final int ALPHA_INDEX_STATE = 0; - private static final int ALPHA_INDEX_REPLACE_TASKBAR = 1; - private static final int NUM_ALPHA_CHANNELS = 2; - // Ratio of empty space, qsb should take up to appear visually centered. public static final float QSB_CENTER_FACTOR = .325f; @@ -52,10 +46,12 @@ public class Hotseat extends CellLayout implements Insettable { @Nullable private Consumer mOnVisibilityAggregatedCallback; - private final MultiValueAlpha mMultiValueAlpha; private final View mQsb; private final int mQsbHeight; + private final View mTaskbarView; + private final int mTaskbarViewHeight; + public Hotseat(Context context) { this(context, null); } @@ -66,12 +62,15 @@ public class Hotseat extends CellLayout implements Insettable { public Hotseat(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mMultiValueAlpha = new MultiValueAlpha(this, NUM_ALPHA_CHANNELS, MultiValueAlpha.Mode.MAX); - mMultiValueAlpha.setUpdateVisibility(true); mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false); mQsbHeight = mQsb.getLayoutParams().height; addView(mQsb); + + 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); } /** @@ -193,6 +192,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 @@ -212,6 +213,13 @@ public class Hotseat extends CellLayout implements Insettable { - (dp.isTaskbarPresent ? dp.taskbarSize : dp.getInsets().bottom); 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; + top = bottom - mTaskbarViewHeight; + mTaskbarView.layout(left, top, right, bottom); } /** @@ -221,12 +229,11 @@ public class Hotseat extends CellLayout implements Insettable { return mWorkspace.getFirstMatch(new CellLayout[] { this }, itemOperator); } - public MultiValueAlpha.AlphaProperty getStateAlpha() { - return mMultiValueAlpha.getProperty(ALPHA_INDEX_STATE); - } - - public MultiValueAlpha.AlphaProperty getReplaceTaskbarAlpha() { - return mMultiValueAlpha.getProperty(ALPHA_INDEX_REPLACE_TASKBAR); + /** + * Sets the alpha value of just our ShortcutAndWidgetContainer. + */ + public void setIconsAlpha(float alpha) { + getShortcutsAndWidgets().setAlpha(alpha); } /** @@ -235,4 +242,11 @@ public class Hotseat extends CellLayout implements Insettable { public View getQsb() { return mQsb; } + + /** + * Returns the Taskbar inside hotseat + */ + public View getTaskbarView() { + return mTaskbarView; + } } diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index e9a34953d5..0f8c6b9172 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -185,12 +185,7 @@ public abstract class LauncherState implements BaseState { } public int getVisibleElements(Launcher launcher) { - DeviceProfile deviceProfile = launcher.getDeviceProfile(); - int flags = WORKSPACE_PAGE_INDICATOR | VERTICAL_SWIPE_INDICATOR | TASKBAR; - if (!deviceProfile.isTaskbarPresent) { - flags |= HOTSEAT_ICONS; - } - return flags; + return HOTSEAT_ICONS | WORKSPACE_PAGE_INDICATOR | VERTICAL_SWIPE_INDICATOR | TASKBAR; } /** diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index 412754e211..cfcf0a0ced 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -54,7 +54,6 @@ import com.android.launcher3.graphics.SysUiScrim; import com.android.launcher3.graphics.WorkspaceDragScrim; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.util.DynamicResource; -import com.android.launcher3.util.MultiValueAlpha; import com.android.systemui.plugins.ResourceProvider; /** @@ -135,8 +134,8 @@ public class WorkspaceStateTransitionAnimation { } float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0; - propertySetter.setFloat(hotseat.getStateAlpha(), MultiValueAlpha.VALUE, - hotseatIconsAlpha, config.getInterpolator(ANIM_HOTSEAT_FADE, fadeInterpolator)); + propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, + config.getInterpolator(ANIM_HOTSEAT_FADE, fadeInterpolator)); float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0; propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(), workspacePageIndicatorAlpha, fadeInterpolator); diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java index f307a53bc0..66575eb289 100644 --- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java +++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java @@ -189,6 +189,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView { case SCROLL_STATE_DRAGGING: mgr.logger().sendToInteractionJankMonitor( LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN, this); + requestFocus(); getWindowInsetsController().hide(WindowInsets.Type.ime()); break; case SCROLL_STATE_IDLE: diff --git a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java index 7fcd6ec16f..0bd2f44cc9 100644 --- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java +++ b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java @@ -22,13 +22,11 @@ import android.graphics.Path; import android.graphics.RectF; import android.view.View; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.R; -import com.android.launcher3.allapps.AllAppsGridAdapter.AppsGridLayoutManager; import com.android.launcher3.allapps.search.SearchAdapterProvider; import com.android.launcher3.allapps.search.SectionDecorationInfo; import com.android.launcher3.util.Themes; @@ -68,28 +66,6 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration { } } - // Fallback logic in case non of the SearchTarget is labeled as focused item. - private void drawDecoration(@NonNull Canvas c, - @NonNull SectionDecorationHandler decorationHandler, - @NonNull RecyclerView parent) { - if (decorationHandler.mIsFullWidth) { - decorationHandler.mBounds.left = parent.getPaddingLeft(); - decorationHandler.mBounds.right = parent.getWidth() - parent.getPaddingRight(); - } - if (mAppsView.getFloatingHeaderView().getFocusedChild() == null - && mAppsView.getApps().getFocusedChild() != null) { - int index = mAppsView.getApps().getFocusedChildIndex(); - AppsGridLayoutManager layoutManager = (AppsGridLayoutManager) - mAppsView.getActiveRecyclerView().getLayoutManager(); - if (layoutManager.findFirstVisibleItemPosition() <= index - && index < parent.getChildCount()) { - RecyclerView.ViewHolder vh = parent.findViewHolderForAdapterPosition(index); - if (vh != null) decorationHandler.onFocusDraw(c, vh.itemView); - } - } - decorationHandler.reset(); - } - /** * Handles grouping and drawing of items in the same all apps sections. */ @@ -136,7 +112,6 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration { */ public void onGroupDraw(Canvas canvas, View view) { if (view == null) return; - mPaint.setColor(mFillcolor); mBounds.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()); onDraw(canvas); diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java index a53fe1f848..373653829b 100644 --- a/src/com/android/launcher3/popup/ArrowPopup.java +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -130,13 +130,14 @@ public abstract class ArrowPopup extends Abstrac R.dimen.popup_arrow_horizontal_center_offset) - (mArrowWidth / 2); mArrowPointRadius = resources.getDimensionPixelSize(R.dimen.popup_arrow_corner_radius); + int smallerRadius = resources.getDimensionPixelSize(R.dimen.popup_smaller_radius); mRoundedTop = new GradientDrawable(); mRoundedTop.setCornerRadii(new float[] { mOutlineRadius, mOutlineRadius, mOutlineRadius, - mOutlineRadius, 0, 0, 0, 0}); + mOutlineRadius, smallerRadius, smallerRadius, smallerRadius, smallerRadius}); mRoundedBottom = new GradientDrawable(); - mRoundedBottom.setCornerRadii(new float[] { 0, 0, 0, 0, mOutlineRadius, mOutlineRadius, - mOutlineRadius, mOutlineRadius}); + mRoundedBottom.setCornerRadii(new float[] { smallerRadius, smallerRadius, smallerRadius, + smallerRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius}); int primaryColor = Themes.getAttrColor(context, R.attr.popupColorPrimary); int secondaryColor = Themes.getAttrColor(context, R.attr.popupColorSecondary); @@ -272,7 +273,6 @@ public abstract class ArrowPopup extends Abstrac } onInflationComplete(reverseOrder); assignMarginsAndBackgrounds(); - orientAboutObject(); if (shouldAddArrow()) { addArrow(); } @@ -286,7 +286,6 @@ public abstract class ArrowPopup extends Abstrac setupForDisplay(); onInflationComplete(false); assignMarginsAndBackgrounds(); - orientAboutObject(); if (shouldAddArrow()) { addArrow(); } @@ -383,10 +382,18 @@ public abstract class ArrowPopup extends Abstrac private void orientAboutObject(boolean allowAlignLeft, boolean allowAlignRight) { measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); - int width = getMeasuredWidth(); int extraVerticalSpace = mArrowHeight + mArrowOffsetVertical + getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding); - int height = getMeasuredHeight() + extraVerticalSpace; + // The margins are added after we call this method, so we need to account for them here. + int numVisibleChildren = 0; + for (int i = getChildCount() - 1; i >= 0; --i) { + if (getChildAt(i).getVisibility() == VISIBLE) { + numVisibleChildren++; + } + } + int childMargins = (numVisibleChildren - 1) * mMargin; + int height = getMeasuredHeight() + extraVerticalSpace + childMargins; + int width = getMeasuredWidth(); getTargetObjectLocation(mTempRect); InsettableFrameLayout dragLayer = getPopupContainer(); diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java index 505c6cea42..71aa4ac445 100644 --- a/src/com/android/launcher3/views/ActivityContext.java +++ b/src/com/android/launcher3/views/ActivityContext.java @@ -18,6 +18,7 @@ package com.android.launcher3.views; import android.content.Context; import android.content.ContextWrapper; import android.graphics.Rect; +import android.view.LayoutInflater; import android.view.View.AccessibilityDelegate; import com.android.launcher3.DeviceProfile; @@ -66,6 +67,18 @@ public interface ActivityContext { default void updateOpenFolderPosition(int[] inOutPosition, Rect bounds, int width, int height) { } + /** + * Returns a LayoutInflater that is cloned in this Context, so that Views inflated by it will + * have the same Context. (i.e. {@link #lookupContext(Context)} will find this ActivityContext.) + */ + default LayoutInflater getLayoutInflater() { + if (this instanceof Context) { + Context context = (Context) this; + return LayoutInflater.from(context).cloneInContext(context); + } + return null; + } + /** * The root view to support drag-and-drop and popup support. */ @@ -73,7 +86,10 @@ public interface ActivityContext { DeviceProfile getDeviceProfile(); - static T lookupContext(Context context) { + /** + * Returns the ActivityContext associated with the given Context. + */ + static T lookupContext(Context context) { if (context instanceof ActivityContext) { return (T) context; } else if (context instanceof ContextWrapper) { diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java index 267f9f72c0..2fda86c89c 100644 --- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java +++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java @@ -119,8 +119,7 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable { public void populateAndShow(ItemInfo itemInfo) { mOriginalItemInfo = itemInfo; - ((TextView) findViewById(R.id.title)).setText(getContext().getString( - R.string.widgets_bottom_sheet_title, mOriginalItemInfo.title)); + ((TextView) findViewById(R.id.title)).setText(mOriginalItemInfo.title); onWidgetsBound(); attachToContainer();