From 3ae3d297e6cf7d994f369756844fd32181b9229b Mon Sep 17 00:00:00 2001 From: samcackett Date: Fri, 25 Oct 2024 16:22:33 +0100 Subject: [PATCH 1/8] Don't allow Desktop tasks to go outside Overview task bounds Wrap TaskThumbnailView's in a new DesktopTaskContentView. This is in order to correctly crop the thumbnail children contained in the DesktopTaskView, otherwise any freeform task screenshots at the edges of the DTV leak outside the bounds. We need a new container to do this, otherwise we will cut off the icon or the hover border if we apply an outline to the DesktopTaskView itself. Fix: 376206104 Flag: com.android.window.flags.enable_desktop_windowing_mode Test: OverviewDesktopTaskImageTest Change-Id: Ic51438e63aaf671a0a8156815d11fc7fa12beac0 --- quickstep/res/layout/task_desktop.xml | 10 ++-- .../quickstep/views/DesktopTaskContentView.kt | 52 +++++++++++++++++++ .../quickstep/views/DesktopTaskView.kt | 25 +++++---- .../android/quickstep/views/TaskContainer.kt | 2 +- .../views/TaskThumbnailViewDeprecated.java | 24 ++++----- 5 files changed, 81 insertions(+), 32 deletions(-) create mode 100644 quickstep/src/com/android/quickstep/views/DesktopTaskContentView.kt diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml index 1564653733..0472007a5a 100644 --- a/quickstep/res/layout/task_desktop.xml +++ b/quickstep/res/layout/task_desktop.xml @@ -19,16 +19,11 @@ android:id="@+id/task_view_desktop" android:layout_width="match_parent" android:layout_height="match_parent" - android:clipChildren="true" - android:clipToPadding="true" android:contentDescription="@string/recent_task_desktop" android:defaultFocusHighlightEnabled="false" android:focusable="true" - android:padding="0.1dp" launcher:focusBorderColor="?attr/materialColorOutline" launcher:hoverBorderColor="?attr/materialColorPrimary"> - + + diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskContentView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskContentView.kt new file mode 100644 index 0000000000..481acac09d --- /dev/null +++ b/quickstep/src/com/android/quickstep/views/DesktopTaskContentView.kt @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2024 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.quickstep.views + +import android.content.Context +import android.graphics.Outline +import android.graphics.Rect +import android.util.AttributeSet +import android.view.View +import android.view.ViewOutlineProvider +import android.widget.FrameLayout +import com.android.quickstep.views.TaskView.FullscreenDrawParams + +class DesktopTaskContentView +@JvmOverloads +constructor(context: Context, attrs: AttributeSet? = null) : FrameLayout(context, attrs) { + private val currentFullscreenParams = FullscreenDrawParams(context) + private val taskCornerRadius: Float + get() = currentFullscreenParams.cornerRadius + + private val bounds = Rect() + + init { + clipToOutline = true + outlineProvider = + object : ViewOutlineProvider() { + override fun getOutline(view: View, outline: Outline) { + outline.setRoundRect(bounds, taskCornerRadius) + } + } + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + bounds.set(0, 0, w, h) + invalidateOutline() + } +} diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt index 15b0a6bcdf..5e842aa741 100644 --- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt +++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt @@ -26,6 +26,7 @@ import android.util.AttributeSet import android.util.Log import android.view.Gravity import android.view.View +import android.widget.FrameLayout import androidx.core.content.res.ResourcesCompat import androidx.core.view.updateLayoutParams import com.android.launcher3.Flags.enableRefactorTaskThumbnail @@ -81,12 +82,12 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu private val tempRect = Rect() private lateinit var backgroundView: View private lateinit var iconView: TaskViewIcon - private var childCountAtInflation = 0 + private lateinit var contentView: FrameLayout override fun onFinishInflate() { super.onFinishInflate() backgroundView = - findViewById(R.id.background)!!.apply { + findViewById(R.id.background).apply { updateLayoutParams { topMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx } @@ -113,7 +114,12 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu ) setText(resources.getText(R.string.recent_task_desktop)) } - childCountAtInflation = childCount + contentView = + findViewById(R.id.desktop_content).apply { + updateLayoutParams { + topMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx + } + } } /** Updates this desktop task to the gives task list defined in `tasks` */ @@ -137,13 +143,8 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu } else { taskThumbnailViewDeprecatedPool!!.view } + contentView.addView(snapshotView, 0) - addView( - snapshotView, - // Add snapshotView to the front after initial views e.g. icon and - // background. - childCountAtInflation, - ) TaskContainer( this, task, @@ -164,7 +165,7 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu super.onRecycle() visibility = VISIBLE taskContainers.forEach { - removeView(it.snapshotView) + contentView.removeView(it.snapshotView) if (enableRefactorTaskThumbnail()) { taskThumbnailViewPool!!.recycle(it.thumbnailView) } else { @@ -227,9 +228,7 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu width = (taskSize.width() * scaleWidth).toInt() height = (taskSize.height() * scaleHeight).toInt() leftMargin = (positionInParent.x * scaleWidth).toInt() - topMargin = - (positionInParent.y * scaleHeight).toInt() + - container.deviceProfile.overviewTaskThumbnailTopMarginPx + topMargin = (positionInParent.y * scaleHeight).toInt() } if (DEBUG) { with(it.snapshotView.layoutParams as LayoutParams) { diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt index 959516fb3b..25aba39c2a 100644 --- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt +++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt @@ -151,7 +151,7 @@ class TaskContainer( if (enableRefactorTaskThumbnail()) { bindThumbnailView() } else { - thumbnailViewDeprecated.bind(task, overlay) + thumbnailViewDeprecated.bind(task, overlay, taskView) } overlay.init() } diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java index 56ca043a79..5dbc2ef915 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java @@ -110,6 +110,7 @@ public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusab private TaskView.FullscreenDrawParams mFullscreenParams; private ImageView mSplashView; private Drawable mSplashViewDrawable; + private TaskView mTaskView; @Nullable private Task mTask; @@ -153,10 +154,11 @@ public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusab /** * Updates the thumbnail to draw the provided task */ - public void bind(Task task, TaskOverlay overlay) { + public void bind(Task task, TaskOverlay overlay, TaskView taskView) { mOverlay = overlay; mOverlay.reset(); mTask = task; + mTaskView = taskView; int color = task == null ? Color.BLACK : task.colorBackground | 0xFF000000; mPaint.setColor(color); mBackgroundPaint.setColor(color); @@ -292,8 +294,8 @@ public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusab public void drawOnCanvas(Canvas canvas, float x, float y, float width, float height, float cornerRadius) { - if (mTask != null && getTaskView().isRunningTask() - && !getTaskView().getShouldShowScreenshot()) { + if (mTask != null && mTaskView.isRunningTask() + && !mTaskView.getShouldShowScreenshot()) { canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mClearPaint); canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mDimmingPaintAfterClearing); @@ -334,10 +336,6 @@ public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusab } } - public TaskView getTaskView() { - return (TaskView) getParent(); - } - public void setOverlayEnabled(boolean overlayEnabled) { if (mOverlayEnabled != overlayEnabled) { mOverlayEnabled = overlayEnabled; @@ -390,9 +388,9 @@ public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusab float viewCenterY = viewHeight / 2f; float centeredDrawableLeft = (viewWidth - drawableWidth) / 2f; float centeredDrawableTop = (viewHeight - drawableHeight) / 2f; - float nonGridScale = getTaskView() == null ? 1 : 1 / getTaskView().getNonGridScale(); - float recentsMaxScale = getTaskView() == null || getTaskView().getRecentsView() == null - ? 1 : 1 / getTaskView().getRecentsView().getMaxScaleForFullScreen(); + float nonGridScale = mTaskView == null ? 1 : 1 / mTaskView.getNonGridScale(); + float recentsMaxScale = mTaskView == null || mTaskView.getRecentsView() == null + ? 1 : 1 / mTaskView.getRecentsView().getMaxScaleForFullScreen(); float scaleX = nonGridScale * recentsMaxScale * (1 / getScaleX()); float scaleY = nonGridScale * recentsMaxScale * (1 / getScaleY()); @@ -419,7 +417,7 @@ public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusab } private boolean isThumbnailRotationDifferentFromTask() { - RecentsView recents = getTaskView().getRecentsView(); + RecentsView recents = mTaskView.getRecentsView(); if (recents == null || mThumbnailData == null) { return false; } @@ -467,7 +465,7 @@ public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusab if (mBitmapShader != null && mThumbnailData != null) { mPreviewRect.set(0, 0, mThumbnailData.getThumbnail().getWidth(), mThumbnailData.getThumbnail().getHeight()); - int currentRotation = getTaskView().getOrientedState().getRecentsActivityRotation(); + int currentRotation = mTaskView.getOrientedState().getRecentsActivityRotation(); boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL; mPreviewPositionHelper.updateThumbnailMatrix(mPreviewRect, mThumbnailData, getMeasuredWidth(), getMeasuredHeight(), dp.isTablet, currentRotation, isRtl); @@ -475,7 +473,7 @@ public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusab mBitmapShader.setLocalMatrix(mPreviewPositionHelper.getMatrix()); mPaint.setShader(mBitmapShader); } - getTaskView().updateCurrentFullscreenParams(); + mTaskView.updateCurrentFullscreenParams(); invalidate(); } From 87455f28fcbfd828612850ea6ebf59da19c6fd83 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 23 Oct 2024 04:39:17 +0000 Subject: [PATCH 2/8] TaskbarManager now sets TaskbarUIController for RecentsWindowManager - FallbackTaskbarUIController can take in a generic RecentsViewContainer parameter, i.e. RecentsActivity or RecentsWindowManager. - When changing Overview targets to RecentsWindowManager, which is not an Activity, we still update the TaskbarUIController Test: Switch between default Home activities with the flag on and off, ensure Taskbar works as expected in each case (3P vs 1P launcher). Flag: com.android.launcher3.enable_fallback_overview_in_window Fixes: 368030750 Fixes: 365775636 Change-Id: Ife775e8c226f8c73ec9e1f97b4a6f2972f6c905f --- .../taskbar/FallbackTaskbarUIController.java | 28 +++++++----- .../launcher3/taskbar/TaskbarManager.java | 45 +++++++++++++++---- .../uioverrides/QuickstepLauncher.java | 8 +++- .../android/quickstep/RecentsActivity.java | 13 ++++-- .../quickstep/TouchInteractionService.java | 11 +++-- .../fallback/window/RecentsWindowManager.kt | 14 ++++++ .../quickstep/views/RecentsViewContainer.java | 11 ++++- .../FallbackTaskbarUIControllerTest.kt | 2 +- 8 files changed, 99 insertions(+), 33 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java index 929e7936e0..e3bcb0df0d 100644 --- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java @@ -25,20 +25,24 @@ import androidx.annotation.Nullable; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.statemanager.StateManager; -import com.android.quickstep.RecentsActivity; +import com.android.launcher3.statemanager.StatefulContainer; import com.android.quickstep.TopTaskTracker; import com.android.quickstep.fallback.RecentsState; import com.android.quickstep.util.TISBindHelper; import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.RecentsViewContainer; import java.util.stream.Stream; /** * A data source which integrates with the fallback RecentsActivity instance (for 3P launchers). + * @param The type of the RecentsViewContainer that will handle Recents state changes. */ -public class FallbackTaskbarUIController extends TaskbarUIController { +public class FallbackTaskbarUIController + > + extends TaskbarUIController { - private final RecentsActivity mRecentsActivity; + private final T mRecentsContainer; private final StateManager.StateListener mStateListener = new StateManager.StateListener() { @@ -63,23 +67,23 @@ public class FallbackTaskbarUIController extends TaskbarUIController { } }; - public FallbackTaskbarUIController(RecentsActivity recentsActivity) { - mRecentsActivity = recentsActivity; + public FallbackTaskbarUIController(T recentsContainer) { + mRecentsContainer = recentsContainer; } @Override protected void init(TaskbarControllers taskbarControllers) { super.init(taskbarControllers); - mRecentsActivity.setTaskbarUIController(this); - mRecentsActivity.getStateManager().addStateListener(mStateListener); + mRecentsContainer.setTaskbarUIController(this); + mRecentsContainer.getStateManager().addStateListener(mStateListener); } @Override protected void onDestroy() { super.onDestroy(); getRecentsView().setTaskLaunchListener(null); - mRecentsActivity.setTaskbarUIController(null); - mRecentsActivity.getStateManager().removeStateListener(mStateListener); + mRecentsContainer.setTaskbarUIController(null); + mRecentsContainer.getStateManager().removeStateListener(mStateListener); } /** @@ -109,7 +113,7 @@ public class FallbackTaskbarUIController extends TaskbarUIController { @Override public RecentsView getRecentsView() { - return mRecentsActivity.getOverviewPanel(); + return mRecentsContainer.getOverviewPanel(); } @Override @@ -131,11 +135,11 @@ public class FallbackTaskbarUIController extends TaskbarUIController { @Nullable @Override protected TISBindHelper getTISBindHelper() { - return mRecentsActivity.getTISBindHelper(); + return mRecentsContainer.getTISBindHelper(); } @Override protected String getTaskbarUIControllerName() { - return "FallbackTaskbarUIController"; + return "FallbackTaskbarUIController<" + mRecentsContainer.getClass().getSimpleName() + ">"; } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index c18cf28996..58a4700685 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -71,7 +71,9 @@ import com.android.launcher3.util.SimpleBroadcastReceiver; import com.android.quickstep.AllAppsActionManager; import com.android.quickstep.RecentsActivity; import com.android.quickstep.SystemUiProxy; +import com.android.quickstep.fallback.window.RecentsWindowManager; import com.android.quickstep.util.ContextualSearchInvoker; +import com.android.quickstep.views.RecentsViewContainer; import com.android.systemui.shared.statusbar.phone.BarTransitions; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; @@ -131,6 +133,8 @@ public class TaskbarManager { private TaskbarActivityContext mTaskbarActivityContext; private StatefulActivity mActivity; + private RecentsViewContainer mRecentsViewContainer; + /** * Cache a copy here so we can initialize state whenever taskbar is recreated, since * this class does not get re-initialized w/ new taskbars. @@ -404,9 +408,28 @@ public class TaskbarManager { } mUnfoldProgressProvider.setSourceProvider(unfoldTransitionProgressProvider); + if (activity instanceof RecentsViewContainer recentsViewContainer) { + setRecentsViewContainer(recentsViewContainer); + } + } + + /** + * Sets the current RecentsViewContainer, from which we create a TaskbarUIController. + */ + public void setRecentsViewContainer(@NonNull RecentsViewContainer recentsViewContainer) { + if (mRecentsViewContainer == recentsViewContainer) { + return; + } + if (mRecentsViewContainer == mActivity) { + // When switching to RecentsWindowManager (not an Activity), the old mActivity is not + // destroyed, nor is there a new Activity to replace it. Thus if we don't clear it here, + // it will not get re-set properly if we return to the Activity (e.g. NexusLauncher). + mActivityOnDestroyCallback.run(); + } + mRecentsViewContainer = recentsViewContainer; if (mTaskbarActivityContext != null) { mTaskbarActivityContext.setUIController( - createTaskbarUIControllerForActivity(mActivity)); + createTaskbarUIControllerForRecentsViewContainer(mRecentsViewContainer)); } } @@ -429,12 +452,18 @@ public class TaskbarManager { /** * Creates a {@link TaskbarUIController} to use while the given StatefulActivity is active. */ - private TaskbarUIController createTaskbarUIControllerForActivity(StatefulActivity activity) { - if (activity instanceof QuickstepLauncher) { - return new LauncherTaskbarUIController((QuickstepLauncher) activity); + private TaskbarUIController createTaskbarUIControllerForRecentsViewContainer( + RecentsViewContainer container) { + if (container instanceof QuickstepLauncher quickstepLauncher) { + return new LauncherTaskbarUIController(quickstepLauncher); } - if (activity instanceof RecentsActivity) { - return new FallbackTaskbarUIController((RecentsActivity) activity); + // If a 3P Launcher is default, always use FallbackTaskbarUIController regardless of + // whether the recents container is RecentsActivity or RecentsWindowManager. + if (container instanceof RecentsActivity recentsActivity) { + return new FallbackTaskbarUIController<>(recentsActivity); + } + if (container instanceof RecentsWindowManager recentsWindowManager) { + return new FallbackTaskbarUIController<>(recentsWindowManager); } return TaskbarUIController.DEFAULT; } @@ -484,9 +513,9 @@ public class TaskbarManager { mSharedState.allAppsVisible = mSharedState.allAppsVisible && isLargeScreenTaskbar; mTaskbarActivityContext.init(mSharedState); - if (mActivity != null) { + if (mRecentsViewContainer != null) { mTaskbarActivityContext.setUIController( - createTaskbarUIControllerForActivity(mActivity)); + createTaskbarUIControllerForRecentsViewContainer(mRecentsViewContainer)); } if (enableTaskbarNoRecreate()) { diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 228dc9101c..fe68ebcd3b 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -139,6 +139,7 @@ import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.taskbar.LauncherTaskbarUIController; import com.android.launcher3.taskbar.TaskbarManager; +import com.android.launcher3.taskbar.TaskbarUIController; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.uioverrides.QuickstepWidgetHolder.QuickstepHolderFactory; @@ -1089,10 +1090,12 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, ); } - public void setTaskbarUIController(LauncherTaskbarUIController taskbarUIController) { - mTaskbarUIController = taskbarUIController; + @Override + public void setTaskbarUIController(@Nullable TaskbarUIController taskbarUIController) { + mTaskbarUIController = (LauncherTaskbarUIController) taskbarUIController; } + @Override public @Nullable LauncherTaskbarUIController getTaskbarUIController() { return mTaskbarUIController; } @@ -1399,6 +1402,7 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, } @NonNull + @Override public TISBindHelper getTISBindHelper() { return mTISBindHelper; } diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java index b19f651bef..6075294709 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/src/com/android/quickstep/RecentsActivity.java @@ -70,6 +70,7 @@ import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.taskbar.FallbackTaskbarUIController; import com.android.launcher3.taskbar.TaskbarManager; +import com.android.launcher3.taskbar.TaskbarUIController; import com.android.launcher3.util.ActivityOptionsWrapper; import com.android.launcher3.util.ContextTracker; import com.android.launcher3.util.RunnableList; @@ -115,7 +116,7 @@ public final class RecentsActivity extends StatefulActivity implem private FallbackRecentsView mFallbackRecentsView; private OverviewActionsView mActionsView; private TISBindHelper mTISBindHelper; - private @Nullable FallbackTaskbarUIController mTaskbarUIController; + private @Nullable FallbackTaskbarUIController mTaskbarUIController; private StateManager mStateManager; @@ -174,11 +175,14 @@ public final class RecentsActivity extends StatefulActivity implem mTISBindHelper.runOnBindToTouchInteractionService(r); } - public void setTaskbarUIController(FallbackTaskbarUIController taskbarUIController) { - mTaskbarUIController = taskbarUIController; + @Override + public void setTaskbarUIController(@Nullable TaskbarUIController taskbarUIController) { + mTaskbarUIController = (FallbackTaskbarUIController) taskbarUIController; } - public FallbackTaskbarUIController getTaskbarUIController() { + @Nullable + @Override + public FallbackTaskbarUIController getTaskbarUIController() { return mTaskbarUIController; } @@ -515,6 +519,7 @@ public final class RecentsActivity extends StatefulActivity implem } @NonNull + @Override public TISBindHelper getTISBindHelper() { return mTISBindHelper; } diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 816258956f..81cfff429b 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -776,10 +776,13 @@ public class TouchInteractionService extends Service { mAllAppsActionManager.setHomeAndOverviewSame(isHomeAndOverviewSame); RecentsViewContainer newOverviewContainer = mOverviewComponentObserver.getContainerInterface().getCreatedContainer(); - if (newOverviewContainer != null - && newOverviewContainer instanceof StatefulActivity activity) { - //TODO(b/368030750) refactor taskbarManager to accept RecentsViewContainer - mTaskbarManager.setActivity(activity); + if (newOverviewContainer != null) { + if (newOverviewContainer instanceof StatefulActivity activity) { + // This will also call setRecentsViewContainer() internally. + mTaskbarManager.setActivity(activity); + } else { + mTaskbarManager.setRecentsViewContainer(newOverviewContainer); + } } mTISBinder.onOverviewTargetChange(); } diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt index 3017df2481..e5f51fe492 100644 --- a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt +++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt @@ -39,6 +39,7 @@ import com.android.launcher3.statehandlers.DesktopVisibilityController import com.android.launcher3.statemanager.StateManager import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory import com.android.launcher3.statemanager.StatefulContainer +import com.android.launcher3.taskbar.TaskbarUIController import com.android.launcher3.util.ContextTracker import com.android.launcher3.util.DisplayController import com.android.launcher3.util.RunnableList @@ -116,6 +117,7 @@ class RecentsWindowManager(context: Context) : private var callbacks: RecentsAnimationCallbacks? = null + private var taskbarUIController: TaskbarUIController? = null private var tisBindHelper: TISBindHelper = TISBindHelper(this) {} // Callback array that corresponds to events defined in @ActivityEvent @@ -285,6 +287,18 @@ class RecentsWindowManager(context: Context) : return tisBindHelper.desktopVisibilityController } + override fun setTaskbarUIController(taskbarUIController: TaskbarUIController?) { + this.taskbarUIController = taskbarUIController + } + + override fun getTaskbarUIController(): TaskbarUIController? { + return taskbarUIController + } + + override fun getTISBindHelper(): TISBindHelper { + return tisBindHelper + } + fun registerInitListener(onInitListener: Predicate) { this.onInitListener = onInitListener } diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java index d8036aa052..b04753b3b8 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java +++ b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java @@ -16,8 +16,6 @@ package com.android.quickstep.views; -import android.app.Activity; -import android.content.ComponentName; import android.content.Context; import android.content.ContextWrapper; import android.content.LocusId; @@ -27,13 +25,16 @@ import android.view.MotionEvent; import android.view.View; import android.view.Window; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.launcher3.BaseActivity; import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.statehandlers.DesktopVisibilityController; +import com.android.launcher3.taskbar.TaskbarUIController; import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.ScrimView; +import com.android.quickstep.util.TISBindHelper; /** * Interface to be implemented by the parent view of RecentsView @@ -212,4 +213,10 @@ public interface RecentsViewContainer extends ActivityContext { @Nullable DesktopVisibilityController getDesktopVisibilityController(); + + void setTaskbarUIController(@Nullable TaskbarUIController taskbarUIController); + + @Nullable TaskbarUIController getTaskbarUIController(); + + @NonNull TISBindHelper getTISBindHelper(); } diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/FallbackTaskbarUIControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/FallbackTaskbarUIControllerTest.kt index 04012c027d..df98606c9f 100644 --- a/quickstep/tests/src/com/android/launcher3/taskbar/FallbackTaskbarUIControllerTest.kt +++ b/quickstep/tests/src/com/android/launcher3/taskbar/FallbackTaskbarUIControllerTest.kt @@ -33,7 +33,7 @@ import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) class FallbackTaskbarUIControllerTest : TaskbarBaseTestCase() { - lateinit var fallbackTaskbarUIController: FallbackTaskbarUIController + lateinit var fallbackTaskbarUIController: FallbackTaskbarUIController lateinit var stateListener: StateManager.StateListener private val recentsActivity: RecentsActivity = mock() From 0c9dc9139468d56436248efee8a32be60f6f897a Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Wed, 30 Oct 2024 18:31:35 -0700 Subject: [PATCH 3/8] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: I2b760d662d7d2b00fd7f3f645dd84b682c2c3842 --- res/values-fr-rCA/strings.xml | 2 +- res/values-it/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml index cae77dc285..a941d8896b 100644 --- a/res/values-fr-rCA/strings.xml +++ b/res/values-fr-rCA/strings.xml @@ -192,7 +192,7 @@ "Espace privé" "Touchez pour configurer ou ouvrir" "Privé" - "Paramètres de l\'Espace privé" + "Paramètres de l\'espace privé" "Privé, déverrouillé." "Privé, verrouillé." "Verrouiller" diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 731f839789..9cdb5aad61 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -192,7 +192,7 @@ "Spazio privato" "Tocca per configurare o aprire" "Privato" - "Impostazioni dello Spazio privato" + "Impostazioni dello spazio privato" "Privato, sbloccato." "Privato, bloccato." "Blocca" From 647266f298538813eef5c5549e881b6cf3fe61c3 Mon Sep 17 00:00:00 2001 From: mpodolian Date: Tue, 29 Oct 2024 14:44:48 -0700 Subject: [PATCH 4/8] Preserve bubble bar state. Added logic to save and then restore existing bubbles in the TaskbarSharedState object. Bug: 375482371 Test: Manual. Switch between pinned and unpinned taskbar. Video: http://recall/-/gx8ASgewUeUS3QYohfrd1J/d8hVHxksAokx85J8P7etoC Flag: com.android.wm.shell.enable_bubble_bar Change-Id: I34f580f1c652859f427385edc0ccadd447e1400f --- .../launcher3/taskbar/TaskbarControllers.java | 2 +- .../launcher3/taskbar/TaskbarSharedState.java | 13 +++++ .../taskbar/bubbles/BubbleBarController.java | 58 ++++++++++++++++++- .../bubbles/BubbleBarViewController.java | 13 ++++- .../taskbar/bubbles/BubbleControllers.java | 6 +- 5 files changed, 85 insertions(+), 7 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java index 4a85acc064..5a63ca69aa 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java @@ -169,7 +169,7 @@ public class TaskbarControllers { taskbarOverlayController.init(this); taskbarAllAppsController.init(this, sharedState.allAppsVisible); navButtonController.init(this); - bubbleControllers.ifPresent(controllers -> controllers.init(this)); + bubbleControllers.ifPresent(controllers -> controllers.init(sharedState, this)); taskbarInsetsController.init(this); voiceInteractionWindowController.init(this); taskbarRecentAppsController.init(this); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java index 729cbe951f..a64dab141c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java @@ -30,6 +30,10 @@ import android.os.IBinder; import android.view.InsetsFrameProvider; import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; +import com.android.wm.shell.shared.bubbles.BubbleBarLocation; +import com.android.wm.shell.shared.bubbles.BubbleInfo; + +import java.util.List; /** * State shared across different taskbar instance @@ -69,6 +73,15 @@ public class TaskbarSharedState { public boolean allAppsVisible = false; + public BubbleBarLocation bubbleBarLocation; + + public List bubbleInfoItems; + + /** Returns whether there are a saved bubbles. */ + public boolean hasSavedBubbles() { + return bubbleInfoItems != null && !bubbleInfoItems.isEmpty(); + } + // LauncherTaskbarUIController#mTaskbarInAppDisplayProgressMultiProp public float[] inAppDisplayProgressMultiPropValues = new float[DISPLAY_PROGRESS_COUNT]; diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java index b22fd6f3d0..30e4e47ff1 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java @@ -35,6 +35,7 @@ import android.os.SystemProperties; import android.util.ArrayMap; import android.util.Log; +import com.android.launcher3.taskbar.TaskbarSharedState; import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController; import com.android.launcher3.util.Executors.SimpleThreadFactory; import com.android.quickstep.SystemUiProxy; @@ -47,6 +48,7 @@ import com.android.wm.shell.shared.bubbles.BubbleInfo; import com.android.wm.shell.shared.bubbles.RemovedBubble; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -112,6 +114,7 @@ public class BubbleBarController extends IBubblesListener.Stub { private BubbleBarItem mSelectedBubble; + private TaskbarSharedState mSharedState; private ImeVisibilityChecker mImeVisibilityChecker; private BubbleBarViewController mBubbleBarViewController; private BubbleStashController mBubbleStashController; @@ -173,12 +176,25 @@ public class BubbleBarController extends IBubblesListener.Stub { public void onDestroy() { mSystemUiProxy.setBubblesListener(null); + // Saves bubble bar state + BubbleInfo[] bubbleInfoItems = new BubbleInfo[mBubbles.size()]; + mBubbles.values().forEach(bubbleBarBubble -> { + int index = mBubbleBarViewController.bubbleViewIndex(bubbleBarBubble.getView()); + if (index < 0 || index >= bubbleInfoItems.length) { + Log.e(TAG, "Found improper index: " + index + " for " + bubbleBarBubble); + } else { + bubbleInfoItems[index] = bubbleBarBubble.getInfo(); + } + }); + mSharedState.bubbleInfoItems = Arrays.asList(bubbleInfoItems); } /** Initializes controllers. */ public void init(BubbleControllers bubbleControllers, BubbleBarLocationListener bubbleBarLocationListener, - ImeVisibilityChecker imeVisibilityChecker) { + ImeVisibilityChecker imeVisibilityChecker, + TaskbarSharedState sharedState) { + mSharedState = sharedState; mImeVisibilityChecker = imeVisibilityChecker; mBubbleBarViewController = bubbleControllers.bubbleBarViewController; mBubbleStashController = bubbleControllers.bubbleStashController; @@ -188,6 +204,7 @@ public class BubbleBarController extends IBubblesListener.Stub { mBubbleBarLocationListener = bubbleBarLocationListener; bubbleControllers.runAfterInit(() -> { + restoreSavedState(sharedState); mBubbleBarViewController.setHiddenForBubbles( !sBubbleBarEnabled || mBubbles.isEmpty()); mBubbleStashedHandleViewController.ifPresent( @@ -266,6 +283,26 @@ public class BubbleBarController extends IBubblesListener.Stub { } } + private void restoreSavedState(TaskbarSharedState sharedState) { + if (sharedState.bubbleBarLocation != null) { + updateBubbleBarLocationInternal(sharedState.bubbleBarLocation); + } + List bubbleInfos = sharedState.bubbleInfoItems; + if (bubbleInfos == null || bubbleInfos.isEmpty()) return; + // Iterate in reverse because new bubbles are added in front and the list is in order. + for (int i = bubbleInfos.size() - 1; i >= 0; i--) { + BubbleBarBubble bubble = mBubbleCreator.populateBubble(mContext, + bubbleInfos.get(i), mBarView, /* existingBubble = */ null); + if (bubble == null) { + Log.e(TAG, "Could not instantiate BubbleBarBubble for " + bubbleInfos.get(i)); + continue; + } + addBubbleInternally(bubble, /* showAppBadge = */ + mBubbleBarViewController.isExpanded() || i == 0, + /* isExpanding = */ false, /* suppressAnimation = */ true); + } + } + private void applyViewChanges(BubbleBarViewUpdate update) { final boolean isCollapsed = (update.expandedChanged && !update.expanded) || (!update.expandedChanged && !mBubbleBarViewController.isExpanded()); @@ -277,6 +314,12 @@ public class BubbleBarController extends IBubblesListener.Stub { update.initialState || mBubbleBarViewController.isHiddenForSysui() || mImeVisibilityChecker.isImeVisible(); + if (update.initialState && mSharedState.hasSavedBubbles()) { + // clear restored state + mBubbleBarViewController.removeAllBubbles(); + mBubbles.clear(); + } + BubbleBarBubble bubbleToSelect = null; if (Flags.enableOptionalBubbleOverflow() @@ -347,8 +390,8 @@ public class BubbleBarController extends IBubblesListener.Stub { for (int i = update.currentBubbles.size() - 1; i >= 0; i--) { BubbleBarBubble bubble = update.currentBubbles.get(i); if (bubble != null) { - mBubbles.put(bubble.getKey(), bubble); - mBubbleBarViewController.addBubble(bubble, isExpanding, suppressAnimation); + addBubbleInternally(bubble, /* showAppBadge = */ !isCollapsed || i == 0, + isExpanding, suppressAnimation); if (isCollapsed) { // If we're collapsed, the most recently added bubble will be selected. bubbleToSelect = bubble; @@ -420,6 +463,7 @@ public class BubbleBarController extends IBubblesListener.Stub { } } if (update.bubbleBarLocation != null) { + mSharedState.bubbleBarLocation = update.bubbleBarLocation; if (update.bubbleBarLocation != mBubbleBarViewController.getBubbleBarLocation()) { updateBubbleBarLocationInternal(update.bubbleBarLocation); } @@ -519,6 +563,14 @@ public class BubbleBarController extends IBubblesListener.Stub { } } + private void addBubbleInternally(BubbleBarBubble bubble, boolean showAppBadge, + boolean isExpanding, boolean suppressAnimation) { + //TODO(b/360652359): remove setting scale to the app badge once issue is fixed + bubble.getView().setBadgeScale(showAppBadge ? 1 : 0); + mBubbles.put(bubble.getKey(), bubble); + mBubbleBarViewController.addBubble(bubble, isExpanding, suppressAnimation); + } + /** Interface for checking whether the IME is visible. */ public interface ImeVisibilityChecker { /** Whether the IME is visible. */ diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java index 31b1ea0a19..bbb0b8bda6 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java @@ -324,6 +324,7 @@ public class BubbleBarViewController { } private void onBubbleClicked(BubbleView bubbleView) { + if (mBubbleBarPinning.isAnimating()) return; bubbleView.markSeen(); BubbleBarItem bubble = bubbleView.getBubble(); if (bubble == null) { @@ -918,7 +919,7 @@ public class BubbleBarViewController { * from Launcher. */ public void setExpanded(boolean isExpanded) { - if (isExpanded != mBarView.isExpanded()) { + if (!mBubbleBarPinning.isAnimating() && isExpanded != mBarView.isExpanded()) { mBarView.setExpanded(isExpanded); adjustTaskbarAndHotseatToBubbleBarState(isExpanded); if (!isExpanded) { @@ -1060,6 +1061,16 @@ public class BubbleBarViewController { mSystemUiProxy.removeAllBubbles(); } + /** Removes all existing bubble views */ + public void removeAllBubbles() { + mBarView.removeAllViews(); + } + + /** Returns the view index of the existing bubble */ + public int bubbleViewIndex(View bubbleView) { + return mBarView.indexOfChild(bubbleView); + } + /** * Set listener to be notified when bubble bar bounds have changed */ diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java index b5d94bdf9e..d993685ee2 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java @@ -21,6 +21,7 @@ import android.graphics.Rect; import android.view.View; import com.android.launcher3.taskbar.TaskbarControllers; +import com.android.launcher3.taskbar.TaskbarSharedState; import com.android.launcher3.taskbar.bubbles.BubbleBarViewController.TaskbarViewPropertiesProvider; import com.android.launcher3.taskbar.bubbles.stashing.BubbleBarLocationOnDemandListener; import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController; @@ -79,7 +80,7 @@ public class BubbleControllers { * BubbleControllers instance, but should be careful to only access things that were created * in constructors for now, as some controllers may still be waiting for init(). */ - public void init(TaskbarControllers taskbarControllers) { + public void init(TaskbarSharedState taskbarSharedState, TaskbarControllers taskbarControllers) { BubbleBarLocationCompositeListener bubbleBarLocationListeners = new BubbleBarLocationCompositeListener( taskbarControllers.navbarButtonsViewController, @@ -88,7 +89,8 @@ public class BubbleControllers { ); bubbleBarController.init(this, bubbleBarLocationListeners, - taskbarControllers.navbarButtonsViewController::isImeVisible); + taskbarControllers.navbarButtonsViewController::isImeVisible, + taskbarSharedState); bubbleStashedHandleViewController.ifPresent( controller -> controller.init(/* bubbleControllers = */ this)); bubbleStashController.init( From 0e8093ae92de2376f57cbb9fda6e39b8188e1a21 Mon Sep 17 00:00:00 2001 From: Liran Binyamin Date: Thu, 31 Oct 2024 12:55:28 -0400 Subject: [PATCH 5/8] Hide bubble dot after flyout init After the flyout initializes to its collapsed state, hide the notification dot so that the flyout and dot will seem visually as one. Flag: com.android.wm.shell.enable_bubble_bar Fixes: 376276297 Test: atest BubbleBarFlyoutControllerTest Change-Id: Ie581ddcd56a26844526f80b2169639c1a7d87500 --- .../bubbles/BubbleBarViewController.java | 9 ++++-- .../launcher3/taskbar/bubbles/BubbleView.java | 15 ++++------ .../animation/BubbleBarViewAnimator.kt | 18 ++++++------ .../flyout/BubbleBarFlyoutController.kt | 8 ++++-- .../flyout/BubbleBarFlyoutControllerTest.kt | 28 +++++++++++-------- 5 files changed, 45 insertions(+), 33 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java index 31b1ea0a19..fef5c7fbb9 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java @@ -872,9 +872,14 @@ public class BubbleBarViewController { /** Animates the bubble bar to notify the user about a bubble change. */ public void animateBubbleNotification(BubbleBarBubble bubble, boolean isExpanding, boolean isUpdate) { - // if we're expanded, don't animate the bubble bar. just show the notification dot. + // if we're not already animating another bubble, update the dot visibility. otherwise the + // the dot will be handled as part of the animation. + if (!mBubbleBarViewAnimator.isAnimating()) { + bubble.getView().updateDotVisibility( + /* animate= */ !mBubbleStashController.isStashed()); + } + // if we're expanded, don't animate the bubble bar. if (isExpanded()) { - bubble.getView().updateDotVisibility(/* animate= */ true); return; } boolean isInApp = mTaskbarStashController.isInApp(); diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java index 4f3e1ae87e..114edf40f8 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java @@ -299,7 +299,8 @@ public class BubbleView extends ConstraintLayout { return mBubble; } - void updateDotVisibility(boolean animate) { + /** Updates the dot visibility if it's not suppressed based on whether it has unseen content. */ + public void updateDotVisibility(boolean animate) { if (mDotSuppressedForBubbleUpdate) { // if the dot is suppressed for an update, there's nothing to do return; @@ -321,16 +322,12 @@ public class BubbleView extends ConstraintLayout { } } - /** - * Suppresses or un-suppresses drawing the dot due to an update for this bubble. - * - *

If the dot is being suppressed and is already visible, it remains visible because it is - * used as a starting point for the animation. If the dot is being unsuppressed, it is - * redrawn if needed. - */ + /** Suppresses or un-suppresses drawing the dot due to an update for this bubble. */ public void suppressDotForBubbleUpdate(boolean suppress) { mDotSuppressedForBubbleUpdate = suppress; - if (!suppress) { + if (suppress) { + setDotScale(0); + } else { showDotIfNeeded(/* animate= */ false); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt index eca2bc8945..6c354f3c0c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt @@ -59,7 +59,7 @@ constructor( private companion object { /** The time to show the flyout. */ - const val FLYOUT_DELAY_MS: Long = 10000 + const val FLYOUT_DELAY_MS: Long = 3000 /** The initial scale Y value that the new bubble is set to before the animation starts. */ const val BUBBLE_ANIMATION_INITIAL_SCALE_Y = 0.3f /** The minimum alpha value to make the bubble bar touchable. */ @@ -484,13 +484,14 @@ constructor( val bubble = bubbleView?.bubble as? BubbleBarBubble val flyout = bubble?.flyoutMessage if (flyout != null) { - bubbleView.suppressDotForBubbleUpdate(true) bubbleBarFlyoutController.setUpAndShowFlyout( - BubbleBarFlyoutMessage(flyout.icon, flyout.title, flyout.message) - ) { - moveToState(AnimatingBubble.State.IN) - bubbleStashController.updateTaskbarTouchRegion() - } + BubbleBarFlyoutMessage(flyout.icon, flyout.title, flyout.message), + onInit = { bubbleView.suppressDotForBubbleUpdate(true) }, + onEnd = { + moveToState(AnimatingBubble.State.IN) + bubbleStashController.updateTaskbarTouchRegion() + }, + ) } else { moveToState(AnimatingBubble.State.IN) } @@ -563,7 +564,8 @@ constructor( if (!bubbleBarFlyoutController.hasFlyout()) { // if the flyout does not yet exist, then we're only animating the bubble bar. // the animating bubble has been updated, so the when the flyout expands it will - // show the right message. + // show the right message. we only need to update the dot visibility. + bubbleView.updateDotVisibility(/* animate= */ !bubbleStashController.isStashed) return } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt index 1452cf6c8c..39e9facddb 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt @@ -59,7 +59,7 @@ constructor( return rect } - fun setUpAndShowFlyout(message: BubbleBarFlyoutMessage, onEnd: () -> Unit) { + fun setUpAndShowFlyout(message: BubbleBarFlyoutMessage, onInit: () -> Unit, onEnd: () -> Unit) { flyout?.let(container::removeView) val flyout = BubbleBarFlyoutView(container.context, positioner, flyoutScheduler) @@ -76,7 +76,11 @@ constructor( container.addView(flyout, lp) this.flyout = flyout - flyout.showFromCollapsed(message) { showFlyout(AnimationType.MORPH, onEnd) } + flyout.showFromCollapsed(message) { + flyout.updateExpansionProgress(0f) + onInit() + showFlyout(AnimationType.MORPH, onEnd) + } } private fun showFlyout(animationType: AnimationType, endAction: () -> Unit) { diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt index fef82c1c50..2997ac9806 100644 --- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt @@ -76,7 +76,7 @@ class BubbleBarFlyoutControllerTest { @Test fun flyoutPosition_left() { InstrumentationRegistry.getInstrumentation().runOnMainSync { - flyoutController.setUpAndShowFlyout(flyoutMessage) {} + setupAndShowFlyout() assertThat(flyoutContainer.childCount).isEqualTo(1) val flyout = flyoutContainer.getChildAt(0) val lp = flyout.layoutParams as FrameLayout.LayoutParams @@ -89,7 +89,7 @@ class BubbleBarFlyoutControllerTest { fun flyoutPosition_right() { onLeft = false InstrumentationRegistry.getInstrumentation().runOnMainSync { - flyoutController.setUpAndShowFlyout(flyoutMessage) {} + setupAndShowFlyout() assertThat(flyoutContainer.childCount).isEqualTo(1) val flyout = flyoutContainer.getChildAt(0) val lp = flyout.layoutParams as FrameLayout.LayoutParams @@ -101,7 +101,7 @@ class BubbleBarFlyoutControllerTest { @Test fun flyoutMessage() { InstrumentationRegistry.getInstrumentation().runOnMainSync { - flyoutController.setUpAndShowFlyout(flyoutMessage) {} + setupAndShowFlyout() assertThat(flyoutContainer.childCount).isEqualTo(1) val flyout = flyoutContainer.getChildAt(0) val sender = flyout.findViewById(R.id.bubble_flyout_title) @@ -114,7 +114,7 @@ class BubbleBarFlyoutControllerTest { @Test fun hideFlyout_removedFromContainer() { InstrumentationRegistry.getInstrumentation().runOnMainSync { - flyoutController.setUpAndShowFlyout(flyoutMessage) {} + setupAndShowFlyout() assertThat(flyoutController.hasFlyout()).isTrue() assertThat(flyoutContainer.childCount).isEqualTo(1) flyoutController.collapseFlyout {} @@ -130,7 +130,7 @@ class BubbleBarFlyoutControllerTest { // boundary flyoutTy = -50f InstrumentationRegistry.getInstrumentation().runOnMainSync { - flyoutController.setUpAndShowFlyout(flyoutMessage) {} + setupAndShowFlyout() assertThat(flyoutContainer.childCount).isEqualTo(1) } InstrumentationRegistry.getInstrumentation().waitForIdleSync() @@ -143,7 +143,7 @@ class BubbleBarFlyoutControllerTest { @Test fun showFlyout_withinBoundary() { InstrumentationRegistry.getInstrumentation().runOnMainSync { - flyoutController.setUpAndShowFlyout(flyoutMessage) {} + setupAndShowFlyout() assertThat(flyoutContainer.childCount).isEqualTo(1) } InstrumentationRegistry.getInstrumentation().waitForIdleSync() @@ -156,7 +156,7 @@ class BubbleBarFlyoutControllerTest { @Test fun collapseFlyout_resetsTopBoundary() { InstrumentationRegistry.getInstrumentation().runOnMainSync { - flyoutController.setUpAndShowFlyout(flyoutMessage) {} + setupAndShowFlyout() assertThat(flyoutContainer.childCount).isEqualTo(1) flyoutController.collapseFlyout {} animatorTestRule.advanceTimeBy(300) @@ -167,7 +167,7 @@ class BubbleBarFlyoutControllerTest { @Test fun cancelFlyout_fadesOutFlyout() { InstrumentationRegistry.getInstrumentation().runOnMainSync { - flyoutController.setUpAndShowFlyout(flyoutMessage) {} + setupAndShowFlyout() assertThat(flyoutContainer.childCount).isEqualTo(1) val flyoutView = flyoutContainer.findViewById(R.id.bubble_bar_flyout_view) assertThat(flyoutView.alpha).isEqualTo(1f) @@ -181,7 +181,7 @@ class BubbleBarFlyoutControllerTest { @Test fun clickFlyout_notifiesCallback() { InstrumentationRegistry.getInstrumentation().runOnMainSync { - flyoutController.setUpAndShowFlyout(flyoutMessage) {} + setupAndShowFlyout() assertThat(flyoutContainer.childCount).isEqualTo(1) val flyoutView = flyoutContainer.findViewById(R.id.bubble_bar_flyout_view) assertThat(flyoutView.alpha).isEqualTo(1f) @@ -194,7 +194,7 @@ class BubbleBarFlyoutControllerTest { @Test fun updateFlyoutWhileExpanding() { InstrumentationRegistry.getInstrumentation().runOnMainSync { - flyoutController.setUpAndShowFlyout(flyoutMessage) {} + setupAndShowFlyout() assertThat(flyoutController.hasFlyout()).isTrue() val flyout = flyoutContainer.findViewById(R.id.bubble_bar_flyout_view) assertThat(flyout.findViewById(R.id.bubble_flyout_text).text) @@ -220,7 +220,7 @@ class BubbleBarFlyoutControllerTest { @Test fun updateFlyoutFullyExpanded() { InstrumentationRegistry.getInstrumentation().runOnMainSync { - flyoutController.setUpAndShowFlyout(flyoutMessage) {} + setupAndShowFlyout() animatorTestRule.advanceTimeBy(300) } assertThat(flyoutController.hasFlyout()).isTrue() @@ -249,7 +249,7 @@ class BubbleBarFlyoutControllerTest { @Test fun updateFlyoutWhileCollapsing() { InstrumentationRegistry.getInstrumentation().runOnMainSync { - flyoutController.setUpAndShowFlyout(flyoutMessage) {} + setupAndShowFlyout() animatorTestRule.advanceTimeBy(300) } assertThat(flyoutController.hasFlyout()).isTrue() @@ -280,6 +280,10 @@ class BubbleBarFlyoutControllerTest { assertThat(flyoutController.hasFlyout()).isTrue() } + private fun setupAndShowFlyout() { + flyoutController.setUpAndShowFlyout(flyoutMessage, {}, {}) + } + class FakeFlyoutCallbacks : FlyoutCallbacks { var topBoundaryExtendedSpace = 0 From 6563429e2bcd95a81cd1ceea408f6b30ca29f3de Mon Sep 17 00:00:00 2001 From: Liran Binyamin Date: Fri, 1 Nov 2024 11:50:59 -0400 Subject: [PATCH 6/8] Update the flyout collapsed position This change ensures that we're updating the distance to the flyout's collapsed position before we start collapsing it. The distance is initially calculated before we start expanding, but when a new bubble is added while we're fully expanded, and if we previously had 1 bubble and now have 2, the collapsed position changed, so we need to update it before we start collapsing. Flag: com.android.wm.shell.enable_bubble_bar Bug: 376276297 Test: manual - dismiss all bubbles - create 1 bubble - after the flyout is fully expanded create a second bubble - observe the flyout is updated with the contents of the second bubble - observe when the flyout collapses, it collapses to the dot on the second bubble Change-Id: I219886fd6463d69692d9945d901d1f3ad3cb26a0 --- .../flyout/BubbleBarFlyoutController.kt | 10 ++++++- .../bubbles/flyout/BubbleBarFlyoutView.kt | 30 +++++++++++-------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt index 39e9facddb..7b20eeab7c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt @@ -164,7 +164,15 @@ constructor( flyout.updateExpansionProgress(animator.animatedValue as Float) } } - animator.addListener(onStart = { flyout.setOnClickListener(null) }, onEnd = { endAction() }) + animator.addListener( + onStart = { + flyout.setOnClickListener(null) + if (animationType == AnimationType.MORPH) { + flyout.updateTranslationToCollapsedPosition() + } + }, + onEnd = { endAction() }, + ) animator.start() } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt index af8aaf8d50..418675c41d 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt @@ -192,18 +192,8 @@ class BubbleBarFlyoutView( title.alpha = 0f message.alpha = 0f setData(flyoutMessage) - val txToCollapsedPosition = - if (positioner.isOnLeft) { - positioner.distanceToCollapsedPosition.x - } else { - -positioner.distanceToCollapsedPosition.x - } - // TODO: b/277815200 - before collapsing, recalculate translationToCollapsedPosition because - // the collapsed position may have changed - val tyToCollapsedPosition = - positioner.distanceToCollapsedPosition.y + triangleHeight - triangleOverlap - translationToCollapsedPosition = PointF(txToCollapsedPosition, tyToCollapsedPosition) + updateTranslationToCollapsedPosition() collapsedSize = positioner.collapsedSize collapsedCornerRadius = collapsedSize / 2 collapsedColor = positioner.collapsedColor @@ -212,7 +202,7 @@ class BubbleBarFlyoutView( // calculate the expansion progress required before we start showing the triangle as part of // the expansion animation minExpansionProgressForTriangle = - positioner.distanceToRevealTriangle / tyToCollapsedPosition + positioner.distanceToRevealTriangle / translationToCollapsedPosition.y // post the request to start the expand animation to the looper so the view can measure // itself @@ -259,6 +249,22 @@ class BubbleBarFlyoutView( message.text = flyoutMessage.message } + /** + * This should be called to update [translationToCollapsedPosition] before we start expanding or + * collapsing to make sure that we're animating the flyout to and from the correct position. + */ + fun updateTranslationToCollapsedPosition() { + val txToCollapsedPosition = + if (positioner.isOnLeft) { + positioner.distanceToCollapsedPosition.x + } else { + -positioner.distanceToCollapsedPosition.x + } + val tyToCollapsedPosition = + positioner.distanceToCollapsedPosition.y + triangleHeight - triangleOverlap + translationToCollapsedPosition = PointF(txToCollapsedPosition, tyToCollapsedPosition) + } + /** Updates the flyout view with the progress of the animation. */ fun updateExpansionProgress(fraction: Float) { expansionProgress = fraction From 50d2c82de627d06ef6fa8035d8f61b98783e57ee Mon Sep 17 00:00:00 2001 From: George Lin Date: Fri, 1 Nov 2024 17:37:55 +0000 Subject: [PATCH 7/8] Fix grid entry is missing Test: Manually tested that the entry shows up again Fixes: 376371559 Flag: EXEMPT bugfix Change-Id: I8ecc842b948f0ed0676d3600d9538450012c7e80 --- .../android/launcher3/graphics/GridCustomizationsProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java index a5bcd0f39f..87c2154032 100644 --- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java +++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java @@ -113,7 +113,8 @@ public class GridCustomizationsProvider extends ContentProvider { switch (uri.getPath()) { case KEY_LIST_OPTIONS: { MatrixCursor cursor = new MatrixCursor(new String[]{ - KEY_NAME, KEY_ROWS, KEY_COLS, KEY_PREVIEW_COUNT, KEY_IS_DEFAULT}); + KEY_NAME, KEY_GRID_TITLE, KEY_ROWS, KEY_COLS, KEY_PREVIEW_COUNT, + KEY_IS_DEFAULT}); InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(getContext()); for (GridOption gridOption : idp.parseAllGridOptions(getContext())) { cursor.newRow() From 2b6f265bf95f737054fffb8dc67e9fe30aab6c5e Mon Sep 17 00:00:00 2001 From: George Lin Date: Thu, 17 Oct 2024 21:12:31 +0000 Subject: [PATCH 8/8] Shape screen communication with the Launcher's app (2/2) This is a revertx2 of ag/29934361 with the fix of b/376371559 Support querying / preview / apply for the shapes from the Launcher's app. Test: Manually tested that it works Fixes: 376371559 Bug: 348664593 Flag: com.android.systemui.shared.new_customization_picker_ui Change-Id: I232040f4c3661f149de4c88810e51f6dd8bac9c3 --- .../graphics/GridCustomizationsProvider.java | 102 +++++++++++++++--- src/com/android/launcher3/shapes/AppShape.kt | 19 ++++ .../launcher3/shapes/AppShapesProvider.kt | 58 ++++++++++ 3 files changed, 167 insertions(+), 12 deletions(-) create mode 100644 src/com/android/launcher3/shapes/AppShape.kt create mode 100644 src/com/android/launcher3/shapes/AppShapesProvider.kt diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java index 87c2154032..7367f2e998 100644 --- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java +++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java @@ -36,18 +36,24 @@ import android.os.Messenger; import android.text.TextUtils; import android.util.Log; +import androidx.annotation.NonNull; + import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.InvariantDeviceProfile.GridOption; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.model.BgDataModel; +import com.android.launcher3.shapes.AppShape; +import com.android.launcher3.shapes.AppShapesProvider; import com.android.launcher3.util.Executors; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.RunnableList; import com.android.systemui.shared.Flags; import java.util.Collections; +import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.ExecutionException; @@ -55,18 +61,25 @@ import java.util.concurrent.ExecutionException; /** * Exposes various launcher grid options and allows the caller to change them. * APIs: - * /list_options: List the various available grip options, has following columns - * name: name of the grid + * /shape_options: List of various available shape options, where each has following fields + * shape_key: key of the shape option + * title: translated title of the shape option + * path: path of the shape, assuming drawn on 100x100 view port + * is_default: true if this shape option is currently set to the system + * + * /list_options: List the various available grid options, where each has following fields + * name: key of the grid option * rows: number of rows in the grid * cols: number of columns in the grid * preview_count: number of previews available for this grid option. The preview uri * looks like /preview// - * is_default: true if this grid is currently active + * is_default: true if this grid option is currently set to the system * - * /preview: Opens a file stream for the grid preview + * /get_preview: Open a file stream for the grid preview * - * /default_grid: Call update to set the current grid, with values - * name: name of the grid to apply + * /default_grid: Call update to set the current shape and grid, with values + * shape_key: key of the shape to apply + * name: key of the grid to apply */ public class GridCustomizationsProvider extends ContentProvider { @@ -77,9 +90,16 @@ public class GridCustomizationsProvider extends ContentProvider { private static final String KEY_ROWS = "rows"; private static final String KEY_COLS = "cols"; private static final String KEY_PREVIEW_COUNT = "preview_count"; + // is_default means if a certain option is currently set to the system private static final String KEY_IS_DEFAULT = "is_default"; + private static final String KEY_SHAPE_KEY = "shape_key"; + private static final String KEY_SHAPE_TITLE = "shape_title"; + private static final String KEY_PATH = "path"; + // list_options is the key for grid option list private static final String KEY_LIST_OPTIONS = "/list_options"; + private static final String KEY_SHAPE_OPTIONS = "/shape_options"; + // default_grid is for setting grid and shape to system settings private static final String KEY_DEFAULT_GRID = "/default_grid"; private static final String METHOD_GET_PREVIEW = "get_preview"; @@ -95,6 +115,7 @@ public class GridCustomizationsProvider extends ContentProvider { public static final String KEY_GRID_NAME = "grid_name"; private static final int MESSAGE_ID_UPDATE_PREVIEW = 1337; + private static final int MESSAGE_ID_UPDATE_SHAPE = 2586; private static final int MESSAGE_ID_UPDATE_GRID = 7414; private static final int MESSAGE_ID_UPDATE_COLOR = 856; @@ -110,7 +131,33 @@ public class GridCustomizationsProvider extends ContentProvider { @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - switch (uri.getPath()) { + Context context = getContext(); + String path = uri.getPath(); + if (context == null || path == null) { + return null; + } + + switch (path) { + case KEY_SHAPE_OPTIONS: { + if (Flags.newCustomizationPickerUi()) { + MatrixCursor cursor = new MatrixCursor(new String[]{ + KEY_SHAPE_KEY, KEY_SHAPE_TITLE, KEY_PATH, KEY_IS_DEFAULT}); + List shapes = AppShapesProvider.INSTANCE.getShapes(); + for (int i = 0; i < shapes.size(); i++) { + AppShape shape = shapes.get(i); + cursor.newRow() + .add(KEY_SHAPE_KEY, shape.getKey()) + .add(KEY_SHAPE_TITLE, shape.getTitle()) + .add(KEY_PATH, shape.getPath()) + // TODO (b/348664593): We should fetch the currently-set shape + // option from the preferences. + .add(KEY_IS_DEFAULT, i == 0); + } + return cursor; + } else { + return null; + } + } case KEY_LIST_OPTIONS: { MatrixCursor cursor = new MatrixCursor(new String[]{ KEY_NAME, KEY_GRID_TITLE, KEY_ROWS, KEY_COLS, KEY_PREVIEW_COUNT, @@ -163,6 +210,14 @@ public class GridCustomizationsProvider extends ContentProvider { } switch (path) { case KEY_DEFAULT_GRID: { + if (Flags.newCustomizationPickerUi()) { + String shapeKey = values.getAsString(KEY_SHAPE_KEY); + Optional optionalShape = AppShapesProvider.INSTANCE.getShapes() + .stream().filter(shape -> shape.getKey().equals(shapeKey)).findFirst(); + String pathToSet = optionalShape.map(AppShape::getPath).orElse(null); + // TODO (b/348664593): Apply shapeName to the system. This needs to be a + // synchronous call. + } String gridName = values.getAsString(KEY_NAME); InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(context); // Verify that this is a valid grid option @@ -220,20 +275,30 @@ public class GridCustomizationsProvider extends ContentProvider { } @Override - public Bundle call(String method, String arg, Bundle extras) { - if (getContext().checkPermission("android.permission.BIND_WALLPAPER", + public Bundle call(@NonNull String method, String arg, Bundle extras) { + Context context = getContext(); + if (context == null) { + return null; + } + + if (context.checkPermission("android.permission.BIND_WALLPAPER", Binder.getCallingPid(), Binder.getCallingUid()) != PackageManager.PERMISSION_GRANTED) { return null; } - if (!METHOD_GET_PREVIEW.equals(method)) { + if (METHOD_GET_PREVIEW.equals(method)) { + return getPreview(extras); + } else { return null; } - return getPreview(extras); } private synchronized Bundle getPreview(Bundle request) { + Context context = getContext(); + if (context == null) { + return null; + } RunnableList lifeCycleTracker = new RunnableList(); try { PreviewSurfaceRenderer renderer = new PreviewSurfaceRenderer( @@ -271,7 +336,9 @@ public class GridCustomizationsProvider extends ContentProvider { public final PreviewSurfaceRenderer renderer; public boolean destroyed = false; - PreviewLifecycleObserver(RunnableList lifeCycleTracker, PreviewSurfaceRenderer renderer) { + PreviewLifecycleObserver( + RunnableList lifeCycleTracker, + PreviewSurfaceRenderer renderer) { this.lifeCycleTracker = lifeCycleTracker; this.renderer = renderer; lifeCycleTracker.add(() -> destroyed = true); @@ -287,6 +354,17 @@ public class GridCustomizationsProvider extends ContentProvider { case MESSAGE_ID_UPDATE_PREVIEW: renderer.hideBottomRow(message.getData().getBoolean(KEY_HIDE_BOTTOM_ROW)); break; + case MESSAGE_ID_UPDATE_SHAPE: + if (Flags.newCustomizationPickerUi()) { + String shapeKey = message.getData().getString(KEY_SHAPE_KEY); + Optional optionalShape = AppShapesProvider.INSTANCE.getShapes() + .stream() + .filter(shape -> shape.getKey().equals(shapeKey)) + .findFirst(); + String pathToSet = optionalShape.map(AppShape::getPath).orElse(null); + // TODO (b/348664593): Update launcher preview with the given shape + } + break; case MESSAGE_ID_UPDATE_GRID: String gridName = message.getData().getString(KEY_GRID_NAME); if (!TextUtils.isEmpty(gridName)) { diff --git a/src/com/android/launcher3/shapes/AppShape.kt b/src/com/android/launcher3/shapes/AppShape.kt new file mode 100644 index 0000000000..68200a0a85 --- /dev/null +++ b/src/com/android/launcher3/shapes/AppShape.kt @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2024 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.shapes + +class AppShape(val key: String, val title: String, val path: String) diff --git a/src/com/android/launcher3/shapes/AppShapesProvider.kt b/src/com/android/launcher3/shapes/AppShapesProvider.kt new file mode 100644 index 0000000000..8c2f181e83 --- /dev/null +++ b/src/com/android/launcher3/shapes/AppShapesProvider.kt @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2024 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.shapes + +import com.android.systemui.shared.Flags + +object AppShapesProvider { + + val shapes = + if (Flags.newCustomizationPickerUi()) + listOf( + AppShape( + "arch", + "arch", + "M100 83.46C100 85.471 100 86.476 99.9 87.321 99.116 93.916 93.916 99.116 87.321 99.9 86.476 100 85.471 100 83.46 100H16.54C14.529 100 13.524 100 12.679 99.9 6.084 99.116.884 93.916.1 87.321 0 86.476 0 85.471 0 83.46L0 50C0 22.386 22.386 0 50 0 77.614 0 100 22.386 100 50V83.46Z", + ), + AppShape( + "4_sided_cookie", + "4 sided cookie", + "M63.605 3C84.733-6.176 106.176 15.268 97 36.395L95.483 39.888C92.681 46.338 92.681 53.662 95.483 60.112L97 63.605C106.176 84.732 84.733 106.176 63.605 97L60.112 95.483C53.662 92.681 46.338 92.681 39.888 95.483L36.395 97C15.267 106.176-6.176 84.732 3 63.605L4.517 60.112C7.319 53.662 7.319 46.338 4.517 39.888L3 36.395C-6.176 15.268 15.267-6.176 36.395 3L39.888 4.517C46.338 7.319 53.662 7.319 60.112 4.517L63.605 3Z", + ), + AppShape( + "seven_sided_cookie", + "7 sided cookie", + "M35.209 4.878C36.326 3.895 36.884 3.404 37.397 3.006 44.82-2.742 55.18-2.742 62.603 3.006 63.116 3.404 63.674 3.895 64.791 4.878 65.164 5.207 65.351 5.371 65.539 5.529 68.167 7.734 71.303 9.248 74.663 9.932 74.902 9.981 75.147 10.025 75.637 10.113 77.1 10.375 77.831 10.506 78.461 10.66 87.573 12.893 94.032 21.011 94.176 30.412 94.186 31.062 94.151 31.805 94.08 33.293 94.057 33.791 94.045 34.04 94.039 34.285 93.958 37.72 94.732 41.121 96.293 44.18 96.404 44.399 96.522 44.618 96.759 45.056 97.467 46.366 97.821 47.021 98.093 47.611 102.032 56.143 99.727 66.266 92.484 72.24 91.983 72.653 91.381 73.089 90.177 73.961 89.774 74.254 89.572 74.4 89.377 74.548 86.647 76.626 84.477 79.353 83.063 82.483 82.962 82.707 82.865 82.936 82.671 83.395 82.091 84.766 81.8 85.451 81.51 86.033 77.31 94.44 67.977 98.945 58.801 96.994 58.166 96.859 57.451 96.659 56.019 96.259 55.54 96.125 55.3 96.058 55.063 95.998 51.74 95.154 48.26 95.154 44.937 95.998 44.699 96.058 44.46 96.125 43.981 96.259 42.549 96.659 41.834 96.859 41.199 96.994 32.023 98.945 22.69 94.44 18.49 86.033 18.2 85.451 17.909 84.766 17.329 83.395 17.135 82.936 17.038 82.707 16.937 82.483 15.523 79.353 13.353 76.626 10.623 74.548 10.428 74.4 10.226 74.254 9.823 73.961 8.619 73.089 8.017 72.653 7.516 72.24.273 66.266-2.032 56.143 1.907 47.611 2.179 47.021 2.533 46.366 3.241 45.056 3.478 44.618 3.596 44.399 3.707 44.18 5.268 41.121 6.042 37.72 5.961 34.285 5.955 34.04 5.943 33.791 5.92 33.293 5.849 31.805 5.814 31.062 5.824 30.412 5.968 21.011 12.427 12.893 21.539 10.66 22.169 10.506 22.9 10.375 24.363 10.113 24.853 10.025 25.098 9.981 25.337 9.932 28.697 9.248 31.833 7.734 34.461 5.529 34.649 5.371 34.836 5.207 35.209 4.878Z", + ), + AppShape( + "sunny", + "sunny", + "M42.846 4.873C46.084-.531 53.916-.531 57.154 4.873L60.796 10.951C62.685 14.103 66.414 15.647 69.978 14.754L76.851 13.032C82.962 11.5 88.5 17.038 86.968 23.149L85.246 30.022C84.353 33.586 85.897 37.315 89.049 39.204L95.127 42.846C100.531 46.084 100.531 53.916 95.127 57.154L89.049 60.796C85.897 62.685 84.353 66.414 85.246 69.978L86.968 76.851C88.5 82.962 82.962 88.5 76.851 86.968L69.978 85.246C66.414 84.353 62.685 85.898 60.796 89.049L57.154 95.127C53.916 100.531 46.084 100.531 42.846 95.127L39.204 89.049C37.315 85.898 33.586 84.353 30.022 85.246L23.149 86.968C17.038 88.5 11.5 82.962 13.032 76.851L14.754 69.978C15.647 66.414 14.103 62.685 10.951 60.796L4.873 57.154C-.531 53.916-.531 46.084 4.873 42.846L10.951 39.204C14.103 37.315 15.647 33.586 14.754 30.022L13.032 23.149C11.5 17.038 17.038 11.5 23.149 13.032L30.022 14.754C33.586 15.647 37.315 14.103 39.204 10.951L42.846 4.873Z", + ), + AppShape( + "circle", + "circle", + "M99.18 50C99.18 77.162 77.162 99.18 50 99.18 22.838 99.18.82 77.162.82 50 .82 22.839 22.838.82 50 .82 77.162.82 99.18 22.839 99.18 50Z", + ), + AppShape( + "square", + "square", + "M99.18 53.689C99.18 67.434 99.18 74.306 97.022 79.758 93.897 87.649 87.649 93.897 79.758 97.022 74.306 99.18 67.434 99.18 53.689 99.18H46.311C32.566 99.18 25.694 99.18 20.242 97.022 12.351 93.897 6.103 87.649 2.978 79.758.82 74.306.82 67.434.82 53.689L.82 46.311C.82 32.566.82 25.694 2.978 20.242 6.103 12.351 12.351 6.103 20.242 2.978 25.694.82 32.566.82 46.311.82L53.689.82C67.434.82 74.306.82 79.758 2.978 87.649 6.103 93.897 12.351 97.022 20.242 99.18 25.694 99.18 32.566 99.18 46.311V53.689Z\n", + ), + ) + else emptyList() +}