From 3f28e0686d55ae0f698aab16ee7970f5e7a8a78a Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Tue, 23 Mar 2021 17:29:31 -0400 Subject: [PATCH 01/15] Update All Apps apps per row when DeviceProfile changes. This fixes the bug where # all apps columns does not change as expected during a grid change. Bug: 183534910 Test: manual, visual Change-Id: Id6a6abd3c7c5e9f36be96eef92961ecfdd477ac9 --- src/com/android/launcher3/allapps/AllAppsContainerView.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 591de043d2..9813bca8a1 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -180,6 +180,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo @Override public void onDeviceProfileChanged(DeviceProfile dp) { for (AdapterHolder holder : mAH) { + holder.adapter.setAppsPerRow(dp.inv.numAllAppsColumns); if (holder.recyclerView != null) { // Remove all views and clear the pool, while keeping the data same. After this // call, all the viewHolders will be recreated. From 6323aa270cd807651eb681120b03fbaabf058264 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Tue, 23 Mar 2021 08:56:40 -0700 Subject: [PATCH 02/15] Enable device search Bug: 183683148 Test: presubmit Change-Id: I464a8ba2bfe0af635d4d0f3a6cd10666e47976ce --- src/com/android/launcher3/config/FeatureFlags.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index 96251f000c..6daecba1a8 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -93,7 +93,7 @@ public final class FeatureFlags { public static final BooleanFlag ENABLE_DEVICE_SEARCH = new DeviceFlag( - "ENABLE_DEVICE_SEARCH", false, "Allows on device search in all apps"); + "ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps"); public static final BooleanFlag FOLDER_NAME_SUGGEST = new DeviceFlag( "FOLDER_NAME_SUGGEST", true, From 00c966a446e6e2b84e825df5bfbe09f8cc9295dc Mon Sep 17 00:00:00 2001 From: Hongwei Wang Date: Thu, 18 Mar 2021 11:12:24 -0700 Subject: [PATCH 03/15] Pass the whole auto pip transaction to recents animation Bug: 179720719 Test: manually using the ApiDemos app Change-Id: I921c97c8bbba66dc5a674d1d67cff2e528e56154 --- .../android/quickstep/AbsSwipeUpHandler.java | 7 +- .../quickstep/RecentsAnimationController.java | 12 +-- .../util/SwipePipToHomeAnimator.java | 88 ++++++++----------- 3 files changed, 47 insertions(+), 60 deletions(-) diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index b49282544d..c50a5ea124 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -46,6 +46,8 @@ import static com.android.quickstep.GestureState.STATE_END_TARGET_SET; import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE; +import static com.android.quickstep.util.SwipePipToHomeAnimator.FRACTION_END; +import static com.android.quickstep.util.SwipePipToHomeAnimator.FRACTION_START; import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS; import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; @@ -1084,7 +1086,7 @@ public abstract class AbsSwipeUpHandler, homeAnimFactory, runningTaskTarget, start); mSwipePipToHomeAnimator.setDuration(SWIPE_PIP_TO_HOME_DURATION); mSwipePipToHomeAnimator.setInterpolator(interpolator); - mSwipePipToHomeAnimator.setFloatValues(0f, 1f); + mSwipePipToHomeAnimator.setFloatValues(FRACTION_START, FRACTION_END); mSwipePipToHomeAnimator.start(); mRunningWindowAnim = RunningWindowAnim.wrap(mSwipePipToHomeAnimator); } else { @@ -1495,8 +1497,7 @@ public abstract class AbsSwipeUpHandler, mRecentsAnimationController.setFinishTaskBounds( mSwipePipToHomeAnimator.getTaskId(), mSwipePipToHomeAnimator.getDestinationBounds(), - mSwipePipToHomeAnimator.getFinishWindowCrop(), - mSwipePipToHomeAnimator.getFinishTransform()); + mSwipePipToHomeAnimator.getFinishTransaction()); mIsSwipingPipToHome = false; } } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java index ec585cc667..82e8a9304c 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java @@ -20,6 +20,7 @@ import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import android.graphics.Rect; +import android.window.PictureInPictureSurfaceTransaction; import androidx.annotation.NonNull; import androidx.annotation.UiThread; @@ -149,14 +150,13 @@ public class RecentsAnimationController { * accordingly. This should be called before `finish` * @param taskId for which the leash should be updated * @param destinationBounds bounds of the final PiP window - * @param windowCrop bounds to crop as part of final transform. - * @param float9 An array of 9 floats to be used as matrix transform. + * @param finishTransaction leash operations for the final transform. */ - public void setFinishTaskBounds(int taskId, Rect destinationBounds, Rect windowCrop, - float[] float9) { + public void setFinishTaskBounds(int taskId, Rect destinationBounds, + PictureInPictureSurfaceTransaction finishTransaction) { UI_HELPER_EXECUTOR.execute( - () -> mController.setFinishTaskBounds(taskId, destinationBounds, windowCrop, - float9)); + () -> mController.setFinishTaskBounds(taskId, destinationBounds, + finishTransaction)); } /** diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java index 0a1a6e8ea0..a1240e0f42 100644 --- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java +++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java @@ -29,6 +29,7 @@ import android.util.Log; import android.view.Surface; import android.view.SurfaceControl; import android.view.View; +import android.window.PictureInPictureSurfaceTransaction; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -46,10 +47,12 @@ import com.android.systemui.shared.system.InteractionJankMonitorWrapper; * Launcher and SysUI. Also, there should be one source of truth for the corner radius of the * PiP window, which would ideally be on SysUI side as well. */ -public class SwipePipToHomeAnimator extends ValueAnimator implements - ValueAnimator.AnimatorUpdateListener { +public class SwipePipToHomeAnimator extends ValueAnimator { private static final String TAG = SwipePipToHomeAnimator.class.getSimpleName(); + public static final float FRACTION_START = 0f; + public static final float FRACTION_END = 1f; + private final int mTaskId; private final ComponentName mComponentName; private final SurfaceControl mLeash; @@ -139,7 +142,7 @@ public class SwipePipToHomeAnimator extends ValueAnimator implements mHasAnimationEnded = true; } }); - addUpdateListener(this); + addUpdateListener(this::onAnimationUpdate); } /** sets the from rotation if it's different from the target rotation. */ @@ -167,48 +170,53 @@ public class SwipePipToHomeAnimator extends ValueAnimator implements mAppBounds.top + mDestinationBounds.height()); } - @Override - public void onAnimationUpdate(ValueAnimator animator) { + private void onAnimationUpdate(ValueAnimator animator) { if (mHasAnimationEnded) return; - - final float fraction = animator.getAnimatedFraction(); - final Rect bounds = mRectEvaluator.evaluate(fraction, mStartBounds, - mDestinationBoundsAnimation); final SurfaceControl.Transaction tx = PipSurfaceTransactionHelper.newSurfaceControlTransaction(); - if (mSourceHintRectInsets == null) { - // no source rect hint been set, directly scale the window down - onAnimationScale(fraction, tx, bounds); - } else { - // scale and crop according to the source rect hint - onAnimationScaleAndCrop(fraction, tx, bounds); - } - mSurfaceTransactionHelper.resetCornerRadius(tx, mLeash); + onAnimationUpdate(tx, animator.getAnimatedFraction()); tx.apply(); } + private PictureInPictureSurfaceTransaction onAnimationUpdate(SurfaceControl.Transaction tx, + float fraction) { + final Rect bounds = mRectEvaluator.evaluate(fraction, mStartBounds, + mDestinationBoundsAnimation); + final PictureInPictureSurfaceTransaction op; + if (mSourceHintRectInsets == null) { + // no source rect hint been set, directly scale the window down + op = onAnimationScale(fraction, tx, bounds); + } else { + // scale and crop according to the source rect hint + op = onAnimationScaleAndCrop(fraction, tx, bounds); + } + return op; + } + /** scale the window directly with no source rect hint being set */ - private void onAnimationScale(float fraction, SurfaceControl.Transaction tx, Rect bounds) { + private PictureInPictureSurfaceTransaction onAnimationScale( + float fraction, SurfaceControl.Transaction tx, Rect bounds) { if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) { final RotatedPosition rotatedPosition = getRotatedPosition(fraction); - mSurfaceTransactionHelper.scale(tx, mLeash, mAppBounds, bounds, + return mSurfaceTransactionHelper.scale(tx, mLeash, mAppBounds, bounds, rotatedPosition.degree, rotatedPosition.positionX, rotatedPosition.positionY); } else { - mSurfaceTransactionHelper.scale(tx, mLeash, mAppBounds, bounds); + return mSurfaceTransactionHelper.scale(tx, mLeash, mAppBounds, bounds); } } /** scale and crop the window with source rect hint */ - private void onAnimationScaleAndCrop(float fraction, SurfaceControl.Transaction tx, + private PictureInPictureSurfaceTransaction onAnimationScaleAndCrop( + float fraction, SurfaceControl.Transaction tx, Rect bounds) { final Rect insets = mInsetsEvaluator.evaluate(fraction, mSourceInsets, mSourceHintRectInsets); if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) { final RotatedPosition rotatedPosition = getRotatedPosition(fraction); - mSurfaceTransactionHelper.scaleAndRotate(tx, mLeash, mAppBounds, bounds, insets, + return mSurfaceTransactionHelper.scaleAndRotate(tx, mLeash, mAppBounds, bounds, insets, rotatedPosition.degree, rotatedPosition.positionX, rotatedPosition.positionY); } else { - mSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mAppBounds, bounds, insets); + return mSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mAppBounds, bounds, insets); } } @@ -224,34 +232,12 @@ public class SwipePipToHomeAnimator extends ValueAnimator implements return mDestinationBounds; } - /** - * @return {@link Rect} of the final window crop in destination orientation. - */ - public Rect getFinishWindowCrop() { - final Rect windowCrop = new Rect(mAppBounds); - if (mSourceHintRectInsets != null) { - windowCrop.inset(mSourceHintRectInsets); - } - return windowCrop; - } - - /** - * @return Array of 9 floats represents the final transform in destination orientation. - */ - public float[] getFinishTransform() { - final Matrix transform = new Matrix(); - final float[] float9 = new float[9]; - if (mSourceHintRectInsets == null) { - transform.setRectToRect(new RectF(mAppBounds), new RectF(mDestinationBounds), - Matrix.ScaleToFit.FILL); - } else { - final float scale = mAppBounds.width() <= mAppBounds.height() - ? (float) mDestinationBounds.width() / mAppBounds.width() - : (float) mDestinationBounds.height() / mAppBounds.height(); - transform.setScale(scale, scale); - } - transform.getValues(float9); - return float9; + /** @return {@link PictureInPictureSurfaceTransaction} for the final leash transaction. */ + public PictureInPictureSurfaceTransaction getFinishTransaction() { + // get the final leash operations but do not apply to the leash. + final SurfaceControl.Transaction tx = + PipSurfaceTransactionHelper.newSurfaceControlTransaction(); + return onAnimationUpdate(tx, FRACTION_END); } private RotatedPosition getRotatedPosition(float fraction) { From b9bbe994eb1252412d5a4c31c6ea51cf88662631 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Thu, 25 Mar 2021 15:09:20 -0700 Subject: [PATCH 04/15] Fix Home->Overview not being logged in 0 button mode At some point we made a change to clearState() from onDragEnd(), which means the detector is in IDLE state instead of SETTLING. As long as we aren't still in DRAGGING state, we should log. Test: wwlogcat Change-Id: I0f1098bd09cd1296b06f8cb3ebe400c2a25156ca --- .../NoButtonNavbarToOverviewTouchController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java index 6c71995f9b..fc06d29ade 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java @@ -203,7 +203,7 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch } private void maybeSwipeInteractionToOverviewComplete() { - if (mReachedOverview && mDetector.isSettlingState()) { + if (mReachedOverview && !mDetector.isDraggingState()) { onSwipeInteractionCompleted(OVERVIEW); } } From 7122bd1577f699419d3f340f4a5eb6ffc9e10c5b Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Thu, 25 Mar 2021 18:07:03 -0500 Subject: [PATCH 05/15] Disable work profile tests Bug: 182844465 Test: presubmit Change-Id: Ifc7baf9dffc6b8b453acf23dfe74f4cc9cd5ba4e --- tests/src/com/android/launcher3/ui/WorkTabTest.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java index 8f4381b0fe..919c89fd56 100644 --- a/tests/src/com/android/launcher3/ui/WorkTabTest.java +++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java @@ -42,7 +42,6 @@ import com.android.launcher3.views.WorkEduView; import org.junit.After; import org.junit.Before; -import org.junit.Test; import org.junit.runner.RunWith; import java.util.List; @@ -90,7 +89,7 @@ public class WorkTabTest extends AbstractLauncherUiTest { }); } - @Test +// @Test public void workTabExists() { mDevice.pressHome(); waitForLauncherCondition("Launcher didn't start", Objects::nonNull); @@ -102,7 +101,7 @@ public class WorkTabTest extends AbstractLauncherUiTest { launcher -> launcher.getAppsView().isWorkTabVisible(), 60000); } - @Test +// @Test public void toggleWorks() { mDevice.pressHome(); waitForLauncherCondition("Launcher didn't start", Objects::nonNull); @@ -133,7 +132,7 @@ public class WorkTabTest extends AbstractLauncherUiTest { l -> l.getSystemService(UserManager.class).isQuietModeEnabled(workProfile)); } - @Test +// @Test public void testWorkEduFlow() { mDevice.pressHome(); waitForLauncherCondition("Launcher didn't start", Objects::nonNull); @@ -176,7 +175,7 @@ public class WorkTabTest extends AbstractLauncherUiTest { }); } - @Test +// @Test public void testWorkEduIntermittent() { mDevice.pressHome(); waitForLauncherCondition("Launcher didn't start", Objects::nonNull); From 0dd46fa242812abbfbe454de2ab85c5878d1ce94 Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Thu, 25 Mar 2021 19:48:03 -0700 Subject: [PATCH 06/15] Enable Live Tile Test: presubmit Fixes: 169694902 Change-Id: Id5cb0dae39a492de6ec54ef843c7492d1626e4db --- src/com/android/launcher3/config/FeatureFlags.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index 7f76d27564..8ae2abd337 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -85,7 +85,7 @@ public final class FeatureFlags { "ADAPTIVE_ICON_WINDOW_ANIM", true, "Use adaptive icons for window animations."); public static final BooleanFlag ENABLE_QUICKSTEP_LIVE_TILE = getDebugFlag( - "ENABLE_QUICKSTEP_LIVE_TILE", false, "Enable live tile in Quickstep overview"); + "ENABLE_QUICKSTEP_LIVE_TILE", true, "Enable live tile in Quickstep overview"); // Keep as DeviceFlag to allow remote disable in emergency. public static final BooleanFlag ENABLE_SUGGESTED_ACTIONS_OVERVIEW = new DeviceFlag( From 733efa1bcdbe2442816ce410616f5a594229c303 Mon Sep 17 00:00:00 2001 From: Zak Cohen Date: Wed, 24 Mar 2021 16:44:21 -0700 Subject: [PATCH 07/15] Overview - extract AssistContentRequester logic for reuse. Extract the logic for fetching AssistContent into a common reusable place. Bug: 179705864 Test: Local build of main launcher Change-Id: Ife37a393d93f899fa1ae460bdcf0cadff6468b04 --- .../quickstep/TaskOverlayFactoryGo.java | 79 ++++---------- .../util/AssistContentRequester.java | 103 ++++++++++++++++++ 2 files changed, 122 insertions(+), 60 deletions(-) create mode 100644 quickstep/src/com/android/quickstep/util/AssistContentRequester.java diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java index 872f168e20..350e0d1d97 100644 --- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java +++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java @@ -20,25 +20,17 @@ import static com.android.quickstep.views.OverviewActionsView.DISABLED_NO_THUMBN import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED; import android.annotation.SuppressLint; -import android.app.ActivityTaskManager; -import android.app.IAssistDataReceiver; import android.app.assist.AssistContent; import android.content.Context; import android.content.Intent; -import android.graphics.Bitmap; import android.graphics.Matrix; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.RemoteException; import android.os.SystemClock; import android.text.TextUtils; -import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.launcher3.R; +import com.android.quickstep.util.AssistContentRequester; import com.android.quickstep.views.OverviewActionsView; import com.android.quickstep.views.TaskThumbnailView; import com.android.systemui.shared.recents.model.Task; @@ -53,7 +45,6 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { public static final String ACTION_SEARCH = "com.android.quickstep.ACTION_SEARCH"; public static final String ELAPSED_NANOS = "niu_actions_elapsed_realtime_nanos"; public static final String ACTIONS_URL = "niu_actions_app_url"; - private static final String ASSIST_KEY_CONTENT = "content"; private static final String TAG = "TaskOverlayFactoryGo"; // Empty constructor required for ResourceBasedOverride @@ -72,13 +63,10 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { */ public static final class TaskOverlayGo extends TaskOverlay { private String mNIUPackageName; - private int mTaskId; - private Bundle mAssistData; - private final Handler mMainThreadHandler; + private String mWebUrl; private TaskOverlayGo(TaskThumbnailView taskThumbnailView) { super(taskThumbnailView); - mMainThreadHandler = new Handler(Looper.getMainLooper()); } /** @@ -99,28 +87,23 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { boolean isAllowedByPolicy = mThumbnailView.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"); - } + int taskId = task.key.id; + AssistContentRequester contentRequester = + new AssistContentRequester(mApplicationContext); + contentRequester.requestAssistContent(taskId, this::onAssistContentReceived); } - /** - * Called when AssistDataReceiverImpl receives data from ActivityTaskManagerService's - * AssistDataRequester - */ - public void onAssistDataReceived(Bundle data) { - mMainThreadHandler.post(() -> { - if (data != null) { - mAssistData = data; - } - }); + /** Provide Assist Content to the overlay. */ + @VisibleForTesting + public void onAssistContentReceived(AssistContent assistContent) { + mWebUrl = assistContent.getWebUri() != null + ? assistContent.getWebUri().toString() : null; + } + + @Override + public void reset() { + super.reset(); + mWebUrl = null; } /** @@ -139,12 +122,8 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { .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()); - } + if (mWebUrl != null) { + intent.putExtra(ACTIONS_URL, mWebUrl); } return intent; @@ -190,26 +169,6 @@ 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/src/com/android/quickstep/util/AssistContentRequester.java b/quickstep/src/com/android/quickstep/util/AssistContentRequester.java new file mode 100644 index 0000000000..3730284ee8 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/AssistContentRequester.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.quickstep.util; + +import android.app.ActivityTaskManager; +import android.app.IActivityTaskManager; +import android.app.IAssistDataReceiver; +import android.app.assist.AssistContent; +import android.content.Context; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.os.RemoteException; +import android.util.Log; + +import com.android.launcher3.util.Executors; + +import java.util.concurrent.Executor; + +/** + * Can be used to request the AssistContent from a provided task id, useful for getting the web uri + * if provided from the task. + */ +public class AssistContentRequester { + private static final String TAG = "AssistContentRequester"; + private static final String ASSIST_KEY_CONTENT = "content"; + + /** For receiving content, called on the main thread. */ + public interface Callback { + /** + * Called when the {@link android.app.assist.AssistContent} of the requested task is + * available. + **/ + void onAssistContentAvailable(AssistContent assistContent); + } + + private final IActivityTaskManager mActivityTaskManager; + private final String mPackageName; + private final Executor mCallbackExecutor; + + public AssistContentRequester(Context context) { + mActivityTaskManager = ActivityTaskManager.getService(); + mPackageName = context.getApplicationContext().getPackageName(); + mCallbackExecutor = Executors.MAIN_EXECUTOR; + } + + /** + * Request the {@link AssistContent} from the task with the provided id. + * + * @param taskId to query for the content. + * @param callback to call when the content is available, called on the main thread. + */ + public void requestAssistContent(int taskId, Callback callback) { + try { + mActivityTaskManager.requestAssistDataForTask( + new AssistDataReceiver(callback, mCallbackExecutor), taskId, mPackageName); + } catch (RemoteException e) { + Log.e(TAG, "Requesting assist content failed for task: " + taskId, e); + } + } + + private static final class AssistDataReceiver extends IAssistDataReceiver.Stub { + + private final Executor mExecutor; + private final Callback mCallback; + + AssistDataReceiver(Callback callback, Executor callbackExecutor) { + mCallback = callback; + mExecutor = callbackExecutor; + } + + @Override + public void onHandleAssistData(Bundle data) { + if (data == null) { + return; + } + + final AssistContent content = data.getParcelable(ASSIST_KEY_CONTENT); + if (content == null) { + Log.e(TAG, "Received AssistData, but no AssistContent found"); + return; + } + + mExecutor.execute(() -> mCallback.onAssistContentAvailable(content)); + } + + @Override + public void onHandleAssistScreenshot(Bitmap screenshot) {} + } +} From c07e3b3c2884976c3aa918e66523f7bc62e0bf50 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Sun, 28 Mar 2021 23:46:50 -0700 Subject: [PATCH 08/15] Remove AA+ decorator logic from aosp code Bug: 179495850 Test: manual Change-Id: I7e029e4970f45a0f7c410533f85335a95e4e448c --- .../launcher3/BaseDraggingActivity.java | 2 +- .../allapps/AllAppsContainerView.java | 3 +- .../launcher3/allapps/AllAppsGridAdapter.java | 3 +- .../allapps/AllAppsSectionDecorator.java | 150 ------------------ .../allapps/AlphabeticalAppsList.java | 10 +- .../launcher3/allapps/DecorationInfo.java | 19 +++ .../allapps/search/AppsSearchPipeline.java | 6 - .../search/DefaultSearchAdapterProvider.java | 23 ++- .../allapps/search/SearchAdapterProvider.java | 12 +- .../allapps/search/SectionDecorationInfo.java | 51 ------ 10 files changed, 53 insertions(+), 226 deletions(-) delete mode 100644 src/com/android/launcher3/allapps/AllAppsSectionDecorator.java create mode 100644 src/com/android/launcher3/allapps/DecorationInfo.java delete mode 100644 src/com/android/launcher3/allapps/search/SectionDecorationInfo.java diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java index e38ab74ee7..9b350a1dd6 100644 --- a/src/com/android/launcher3/BaseDraggingActivity.java +++ b/src/com/android/launcher3/BaseDraggingActivity.java @@ -329,6 +329,6 @@ public abstract class BaseDraggingActivity extends BaseActivity * views */ public SearchAdapterProvider createSearchAdapterProvider(AllAppsContainerView allapps) { - return new DefaultSearchAdapterProvider(this); + return new DefaultSearchAdapterProvider(this, allapps); } } diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index bf0a88f33f..949cd2e500 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -699,8 +699,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo applyPadding(); setupOverlay(); if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) { - recyclerView.addItemDecoration(new AllAppsSectionDecorator( - AllAppsContainerView.this)); + recyclerView.addItemDecoration(mSearchAdapterProvider.getDecorator()); } } diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java index bb175eac28..5b4c4c5c36 100644 --- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java +++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java @@ -42,7 +42,6 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.BubbleTextView; import com.android.launcher3.R; import com.android.launcher3.allapps.search.SearchAdapterProvider; -import com.android.launcher3.allapps.search.SectionDecorationInfo; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.util.PackageManagerHelper; @@ -108,7 +107,7 @@ public class AllAppsGridAdapter extends // The index of this app not including sections public int appIndex = -1; // Search section associated to result - public SectionDecorationInfo sectionDecorationInfo = null; + public DecorationInfo decorationInfo = null; /** * Factory method for AppIcon AdapterItem diff --git a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java deleted file mode 100644 index 0bd2f44cc9..0000000000 --- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.allapps; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.RectF; -import android.view.View; - -import androidx.annotation.Nullable; -import androidx.core.graphics.ColorUtils; -import androidx.recyclerview.widget.RecyclerView; - -import com.android.launcher3.R; -import com.android.launcher3.allapps.search.SearchAdapterProvider; -import com.android.launcher3.allapps.search.SectionDecorationInfo; -import com.android.launcher3.util.Themes; - -import java.util.List; - -/** - * ItemDecoration class that groups items in {@link AllAppsRecyclerView} - */ -public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration { - - private final AllAppsContainerView mAppsView; - - AllAppsSectionDecorator(AllAppsContainerView appsContainerView) { - mAppsView = appsContainerView; - } - - @Override - public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { - List adapterItems = mAppsView.getApps().getAdapterItems(); - SearchAdapterProvider adapterProvider = mAppsView.getSearchAdapterProvider(); - for (int i = 0; i < parent.getChildCount(); i++) { - View view = parent.getChildAt(i); - int position = parent.getChildAdapterPosition(view); - AllAppsGridAdapter.AdapterItem adapterItem = adapterItems.get(position); - if (adapterItem.sectionDecorationInfo != null) { - SectionDecorationInfo sectionInfo = adapterItem.sectionDecorationInfo; - SectionDecorationHandler decorationHandler = sectionInfo.getDecorationHandler(); - if (decorationHandler != null) { - if (view.equals(adapterProvider.getHighlightedItem())) { - decorationHandler.onFocusDraw(c, view); - } else { - decorationHandler.onGroupDraw(c, view); - } - } - } - } - } - - /** - * Handles grouping and drawing of items in the same all apps sections. - */ - public static class SectionDecorationHandler { - protected RectF mBounds = new RectF(); - private final boolean mIsFullWidth; - private final float mRadius; - - protected final int mFocusColor; // main focused item color - protected final int mFillcolor; // grouping color - - private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private final boolean mIsTopRound; - private final boolean mIsBottomRound; - private float[] mCorners; - private float mFillSpacing; - - public SectionDecorationHandler(Context context, boolean isFullWidth, int fillAlpha, - boolean isTopRound, boolean isBottomRound) { - - mIsFullWidth = isFullWidth; - int endScrim = Themes.getColorBackground(context); - mFillcolor = ColorUtils.setAlphaComponent(endScrim, fillAlpha); - mFocusColor = endScrim; - - mIsTopRound = isTopRound; - mIsBottomRound = isBottomRound; - - mRadius = context.getResources().getDimensionPixelSize( - R.dimen.search_decoration_corner_radius); - mFillSpacing = context.getResources().getDimensionPixelSize( - R.dimen.search_decoration_padding); - mCorners = new float[]{ - mIsTopRound ? mRadius : 0, mIsTopRound ? mRadius : 0, // Top left radius in px - mIsTopRound ? mRadius : 0, mIsTopRound ? mRadius : 0, // Top right radius in px - mIsBottomRound ? mRadius : 0, mIsBottomRound ? mRadius : 0, // Bottom right - mIsBottomRound ? mRadius : 0, mIsBottomRound ? mRadius : 0 // Bottom left - }; - - } - - /** - * Draw bounds onto canvas. - */ - 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); - } - - /** - * Draw the bound of the view to the canvas. - */ - public void onFocusDraw(Canvas canvas, @Nullable View view) { - if (view == null) { - return; - } - mPaint.setColor(mFocusColor); - mBounds.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()); - onDraw(canvas); - } - - - private void onDraw(Canvas canvas) { - final Path path = new Path(); - RectF finalBounds = new RectF(mBounds.left + mFillSpacing, - mBounds.top + mFillSpacing, - mBounds.right - mFillSpacing, - mBounds.bottom - mFillSpacing); - path.addRoundRect(finalBounds, mCorners, Path.Direction.CW); - canvas.drawPath(path, mPaint); - } - - /** - * Reset view bounds to empty. - */ - public void reset() { - mBounds.setEmpty(); - } - } -} diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java index fefd97ad3f..6957850730 100644 --- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java @@ -20,7 +20,6 @@ import android.content.Context; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem; -import com.android.launcher3.allapps.search.SectionDecorationInfo; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.util.ItemInfoMatcher; @@ -288,11 +287,6 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener { mFastScrollerSections.clear(); mAdapterItems.clear(); - SectionDecorationInfo appSection = new SectionDecorationInfo(); - appSection.setDecorationHandler( - new AllAppsSectionDecorator.SectionDecorationHandler(mLauncher, true, - 0, false, false)); - // Recreate the filtered and sectioned apps (for convenience for the grid layout) from the // ordered set of sections @@ -313,9 +307,7 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener { if (lastFastScrollerSectionInfo.fastScrollToItem == null) { lastFastScrollerSectionInfo.fastScrollToItem = appItem; } - if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) { - appItem.sectionDecorationInfo = appSection; - } + mAdapterItems.add(appItem); } } else { diff --git a/src/com/android/launcher3/allapps/DecorationInfo.java b/src/com/android/launcher3/allapps/DecorationInfo.java new file mode 100644 index 0000000000..50b250cad1 --- /dev/null +++ b/src/com/android/launcher3/allapps/DecorationInfo.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.allapps; + +public class DecorationInfo { +} diff --git a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java b/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java index 34895ed5f5..42ee4b78be 100644 --- a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java +++ b/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java @@ -20,7 +20,6 @@ import android.os.CancellationSignal; import com.android.launcher3.LauncherAppState; import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem; -import com.android.launcher3.allapps.AllAppsSectionDecorator.SectionDecorationHandler; import com.android.launcher3.model.AllAppsList; import com.android.launcher3.model.BaseModelUpdateTask; import com.android.launcher3.model.BgDataModel; @@ -38,14 +37,10 @@ public class AppsSearchPipeline implements SearchPipeline { private static final int MAX_RESULTS_COUNT = 5; - private final SectionDecorationInfo mSearchSectionInfo; private final LauncherAppState mLauncherAppState; public AppsSearchPipeline(Context context, LauncherAppState launcherAppState) { mLauncherAppState = launcherAppState; - mSearchSectionInfo = new SectionDecorationInfo(); - mSearchSectionInfo.setDecorationHandler( - new SectionDecorationHandler(context, true, 0, true, true)); } @Override @@ -82,7 +77,6 @@ public class AppsSearchPipeline implements SearchPipeline { ArrayList items = new ArrayList<>(); for (int i = 0; i < matchingApps.size() && i < MAX_RESULTS_COUNT; i++) { AdapterItem appItem = AdapterItem.asApp(i, "", matchingApps.get(i), i); - appItem.sectionDecorationInfo = mSearchSectionInfo; items.add(appItem); } diff --git a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java index ba895ed5d4..ef62da43af 100644 --- a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java +++ b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java @@ -15,12 +15,17 @@ */ package com.android.launcher3.allapps.search; +import android.graphics.Canvas; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.BubbleTextView; +import com.android.launcher3.allapps.AllAppsContainerView; import com.android.launcher3.allapps.AllAppsGridAdapter; import com.android.launcher3.model.data.ItemInfo; @@ -29,10 +34,19 @@ import com.android.launcher3.model.data.ItemInfo; */ public class DefaultSearchAdapterProvider extends SearchAdapterProvider { + private final RecyclerView.ItemDecoration mDecoration; private View mHighlightedView; - public DefaultSearchAdapterProvider(BaseDraggingActivity launcher) { - super(launcher); + public DefaultSearchAdapterProvider(BaseDraggingActivity launcher, + AllAppsContainerView appsContainerView) { + super(launcher, appsContainerView); + mDecoration = new RecyclerView.ItemDecoration() { + @Override + public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, + @NonNull RecyclerView.State state) { + super.onDraw(c, parent, state); + } + }; } @Override @@ -67,4 +81,9 @@ public class DefaultSearchAdapterProvider extends SearchAdapterProvider { public View getHighlightedItem() { return mHighlightedView; } + + @Override + public RecyclerView.ItemDecoration getDecorator() { + return mDecoration; + } } diff --git a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java index a650a7d947..cefb8cbdd8 100644 --- a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java +++ b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java @@ -21,7 +21,10 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.recyclerview.widget.RecyclerView; + import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.allapps.AllAppsContainerView; import com.android.launcher3.allapps.AllAppsGridAdapter; /** @@ -31,7 +34,7 @@ public abstract class SearchAdapterProvider { protected final BaseDraggingActivity mLauncher; - public SearchAdapterProvider(BaseDraggingActivity launcher) { + public SearchAdapterProvider(BaseDraggingActivity launcher, AllAppsContainerView appsView) { mLauncher = launcher; } @@ -72,7 +75,7 @@ public abstract class SearchAdapterProvider { } /** - * handles selection event on search adapter item. Returns false if provider can not handle + * Handles selection event on search adapter item. Returns false if provider can not handle * event */ public abstract boolean launchHighlightedItem(); @@ -82,5 +85,8 @@ public abstract class SearchAdapterProvider { */ public abstract View getHighlightedItem(); - + /** + * Returns the item decorator. + */ + public abstract RecyclerView.ItemDecoration getDecorator(); } diff --git a/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java b/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java deleted file mode 100644 index 56dd63ccc1..0000000000 --- a/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.allapps.search; - -import com.android.launcher3.allapps.AllAppsSectionDecorator.SectionDecorationHandler; - -/** - * Info class for a search section that is primarily used for decoration. - */ -public class SectionDecorationInfo { - public static final int GROUPING = 1 << 1; - - private String mSectionId; - private SectionDecorationHandler mDecorationHandler; - - public SectionDecorationInfo() { - this(null); - } - - public SectionDecorationInfo(String sectionId) { - mSectionId = sectionId; - } - - public void setDecorationHandler(SectionDecorationHandler sectionDecorationHandler) { - mDecorationHandler = sectionDecorationHandler; - } - - public SectionDecorationHandler getDecorationHandler() { - return mDecorationHandler; - } - - /** - * Returns the section's ID - */ - public String getSectionId() { - return mSectionId == null ? "" : mSectionId; - } -} From 41a842449d0f640945538e8b0a80dcf1e7535754 Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Mon, 29 Mar 2021 13:01:28 +0100 Subject: [PATCH 09/15] Don't transpose hotseat on sw600 Bug: 178385459 Test: Manual Change-Id: I5805b0ccb05b97b931ab99a31c31029f7066daca --- res/values-sw600dp/config.xml | 3 +++ res/values-sw720dp/config.xml | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/res/values-sw600dp/config.xml b/res/values-sw600dp/config.xml index 09bdaafc1d..d50115b20d 100644 --- a/res/values-sw600dp/config.xml +++ b/res/values-sw600dp/config.xml @@ -1,3 +1,6 @@ true + + + false diff --git a/res/values-sw720dp/config.xml b/res/values-sw720dp/config.xml index ec07591ff9..33fc553a84 100644 --- a/res/values-sw720dp/config.xml +++ b/res/values-sw720dp/config.xml @@ -3,7 +3,4 @@ 90 - - - false From c5797893e7327d300b6c9549ab6d93d6d7a0e387 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 29 Mar 2021 12:26:05 -0700 Subject: [PATCH 10/15] Using edgeEffect for overscroll in all-apps and widget tray Bug: 183966408 Test: Manual Change-Id: Iea1b67504fc59fc7ce2ec657bf8ac7e3d8bfff1c --- .../allapps/AllAppsContainerView.java | 28 +-- .../launcher3/views/SpringRelativeLayout.java | 179 ++++++++---------- .../widget/picker/WidgetsFullSheet.java | 5 - 3 files changed, 78 insertions(+), 134 deletions(-) diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index bf0a88f33f..60dd77435d 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -77,7 +77,7 @@ import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePag public class AllAppsContainerView extends SpringRelativeLayout implements DragSource, Insettable, OnDeviceProfileChangeListener, OnActivePageChangedListener { - private static final float FLING_VELOCITY_MULTIPLIER = 135f; + private static final float FLING_VELOCITY_MULTIPLIER = 1000 * .8f; // Starts the springs after at least 55% of the animation has passed. private static final float FLING_ANIMATION_THRESHOLD = 0.55f; private static final int ALPHA_CHANNEL_COUNT = 2; @@ -140,12 +140,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo mAllAppsStore.addUpdateListener(this::onAppsUpdated); - addSpringView(R.id.all_apps_header); - addSpringView(R.id.apps_list_view); - addSpringView(R.id.all_apps_tabs_view_pager); - mMultiValueAlpha = new MultiValueAlpha(this, ALPHA_CHANNEL_COUNT); - } /** @@ -169,14 +164,6 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo return mWorkModeSwitch; } - - @Override - protected void setDampedScrollShift(float shift) { - // Bound the shift amount to avoid content from drawing on top (Y-val) of the QSB. - float maxShift = getSearchView().getHeight() / 2f; - super.setDampedScrollShift(Utilities.boundToRange(shift, -maxShift, maxShift)); - } - @Override public void onDeviceProfileChanged(DeviceProfile dp) { for (AdapterHolder holder : mAH) { @@ -407,12 +394,6 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo } } - @Override - public int getCanvasClipTopForOverscroll() { - // Do not clip if the QSB is attached to the spring, otherwise the QSB will get clipped. - return mSpringViews.get(getSearchView().getId()) ? 0 : mHeader.getTop(); - } - private void rebindAdapters(boolean showTabs) { rebindAdapters(showTabs, false /* force */); } @@ -639,11 +620,8 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo public void onAnimationUpdate(ValueAnimator valueAnimator) { if (shouldSpring && valueAnimator.getAnimatedFraction() >= FLING_ANIMATION_THRESHOLD) { - int searchViewId = getSearchView().getId(); - addSpringView(searchViewId); - finishWithShiftAndVelocity(1, velocity * FLING_VELOCITY_MULTIPLIER, - (anim, canceled, value, velocity) -> removeSpringView(searchViewId)); - + absorbSwipeUpVelocity(Math.abs( + Math.round(velocity * FLING_VELOCITY_MULTIPLIER))); shouldSpring = false; } } diff --git a/src/com/android/launcher3/views/SpringRelativeLayout.java b/src/com/android/launcher3/views/SpringRelativeLayout.java index d0ec9d7e08..9701389f91 100644 --- a/src/com/android/launcher3/views/SpringRelativeLayout.java +++ b/src/com/android/launcher3/views/SpringRelativeLayout.java @@ -15,51 +15,25 @@ */ package com.android.launcher3.views; -import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY; -import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW; -import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_MEDIUM; - import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; -import android.util.SparseBooleanArray; -import android.view.View; import android.widget.EdgeEffect; import android.widget.RelativeLayout; import androidx.annotation.NonNull; -import androidx.dynamicanimation.animation.DynamicAnimation; -import androidx.dynamicanimation.animation.FloatPropertyCompat; -import androidx.dynamicanimation.animation.SpringAnimation; -import androidx.dynamicanimation.animation.SpringForce; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory; +import com.android.launcher3.Utilities; + +/** + * View group to allow rendering overscroll effect in a child at the parent level + */ public class SpringRelativeLayout extends RelativeLayout { - private static final float STIFFNESS = (STIFFNESS_MEDIUM + STIFFNESS_LOW) / 2; - private static final float DAMPING_RATIO = DAMPING_RATIO_MEDIUM_BOUNCY; - private static final float VELOCITY_MULTIPLIER = 0.3f; - - private static final FloatPropertyCompat DAMPED_SCROLL = - new FloatPropertyCompat("value") { - - @Override - public float getValue(SpringRelativeLayout object) { - return object.mDampedScrollShift; - } - - @Override - public void setValue(SpringRelativeLayout object, float value) { - object.setDampedScrollShift(value); - } - }; - - protected final SparseBooleanArray mSpringViews = new SparseBooleanArray(); - private final SpringAnimation mSpring; - - private float mDampedScrollShift = 0; - private SpringEdgeEffect mActiveEdge; + private final EdgeEffect mEdgeGlowTop; + private final EdgeEffect mEdgeGlowBottom; public SpringRelativeLayout(Context context) { this(context, null); @@ -71,98 +45,73 @@ public class SpringRelativeLayout extends RelativeLayout { public SpringRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - mSpring = new SpringAnimation(this, DAMPED_SCROLL, 0); - mSpring.setSpring(new SpringForce(0) - .setStiffness(STIFFNESS) - .setDampingRatio(DAMPING_RATIO)); - } - - public void addSpringView(int id) { - mSpringViews.put(id, true); - } - - public void removeSpringView(int id) { - mSpringViews.delete(id); - invalidate(); - } - - /** - * Used to clip the canvas when drawing child views during overscroll. - */ - public int getCanvasClipTopForOverscroll() { - return 0; + mEdgeGlowTop = Utilities.ATLEAST_S + ? new EdgeEffect(context, attrs) : new EdgeEffect(context); + mEdgeGlowBottom = Utilities.ATLEAST_S + ? new EdgeEffect(context, attrs) : new EdgeEffect(context); + setWillNotDraw(false); } @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - if (mDampedScrollShift != 0 && mSpringViews.get(child.getId())) { - int saveCount = canvas.save(); - - canvas.clipRect(0, getCanvasClipTopForOverscroll(), getWidth(), getHeight()); - canvas.translate(0, mDampedScrollShift); - boolean result = super.drawChild(canvas, child, drawingTime); - - canvas.restoreToCount(saveCount); - - return result; + public void draw(Canvas canvas) { + super.draw(canvas); + if (!mEdgeGlowTop.isFinished()) { + final int restoreCount = canvas.save(); + canvas.translate(0, 0); + mEdgeGlowTop.setSize(getWidth(), getHeight()); + if (mEdgeGlowTop.draw(canvas)) { + postInvalidateOnAnimation(); + } + canvas.restoreToCount(restoreCount); } - return super.drawChild(canvas, child, drawingTime); - } - - private void setActiveEdge(SpringEdgeEffect edge) { - if (mActiveEdge != edge && mActiveEdge != null) { - mActiveEdge.mDistance = 0; - } - mActiveEdge = edge; - } - - protected void setDampedScrollShift(float shift) { - if (shift != mDampedScrollShift) { - mDampedScrollShift = shift; - invalidate(); + if (!mEdgeGlowBottom.isFinished()) { + final int restoreCount = canvas.save(); + final int width = getWidth(); + final int height = getHeight(); + canvas.translate(-width, height); + canvas.rotate(180, width, 0); + mEdgeGlowBottom.setSize(width, height); + if (mEdgeGlowBottom.draw(canvas)) { + postInvalidateOnAnimation(); + } + canvas.restoreToCount(restoreCount); } } - private void finishScrollWithVelocity(float velocity) { - mSpring.setStartVelocity(velocity); - mSpring.setStartValue(mDampedScrollShift); - mSpring.start(); - } - protected void finishWithShiftAndVelocity(float shift, float velocity, - DynamicAnimation.OnAnimationEndListener listener) { - setDampedScrollShift(shift); - mSpring.addEndListener(listener); - finishScrollWithVelocity(velocity); + /** + * Absorbs the velocity as a result for swipe-up fling + */ + protected void absorbSwipeUpVelocity(int velocity) { + mEdgeGlowBottom.onAbsorb(velocity); + invalidate(); } public EdgeEffectFactory createEdgeEffectFactory() { - return new SpringEdgeEffectFactory(); + return new ProxyEdgeEffectFactory(); } - private class SpringEdgeEffectFactory extends EdgeEffectFactory { + private class ProxyEdgeEffectFactory extends EdgeEffectFactory { @NonNull @Override protected EdgeEffect createEdgeEffect(RecyclerView view, int direction) { switch (direction) { case DIRECTION_TOP: - return new SpringEdgeEffect(getContext(), +VELOCITY_MULTIPLIER); + return new EdgeEffectProxy(getContext(), mEdgeGlowTop); case DIRECTION_BOTTOM: - return new SpringEdgeEffect(getContext(), -VELOCITY_MULTIPLIER); + return new EdgeEffectProxy(getContext(), mEdgeGlowBottom); } return super.createEdgeEffect(view, direction); } } - private class SpringEdgeEffect extends EdgeEffect { + private class EdgeEffectProxy extends EdgeEffect { - private final float mVelocityMultiplier; + private final EdgeEffect mParent; - private float mDistance; - - public SpringEdgeEffect(Context context, float velocityMultiplier) { + EdgeEffectProxy(Context context, EdgeEffect parent) { super(context); - mVelocityMultiplier = velocityMultiplier; + mParent = parent; } @Override @@ -170,22 +119,44 @@ public class SpringRelativeLayout extends RelativeLayout { return false; } + private void invalidateParentScrollEffect() { + if (!mParent.isFinished()) { + invalidate(); + } + } + @Override public void onAbsorb(int velocity) { - finishScrollWithVelocity(velocity * mVelocityMultiplier); + mParent.onAbsorb(velocity); + invalidateParentScrollEffect(); + } + + @Override + public void onPull(float deltaDistance) { + mParent.onPull(deltaDistance); + invalidateParentScrollEffect(); } @Override public void onPull(float deltaDistance, float displacement) { - setActiveEdge(this); - mDistance += deltaDistance * (mVelocityMultiplier / 3f); - setDampedScrollShift(mDistance * getHeight()); + mParent.onPull(deltaDistance, displacement); + invalidateParentScrollEffect(); } @Override public void onRelease() { - mDistance = 0; - finishScrollWithVelocity(0); + mParent.onRelease(); + invalidateParentScrollEffect(); + } + + @Override + public void finish() { + mParent.finish(); + } + + @Override + public boolean isFinished() { + return mParent.isFinished(); } } } \ No newline at end of file diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java index 29c00b209f..d13884ad9e 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java +++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java @@ -144,17 +144,12 @@ public class WidgetsFullSheet extends BaseWidgetSheet findViewById(R.id.tab_work) .setOnClickListener((View view) -> mViewPager.snapToPage(1)); fastScroller.setIsRecyclerViewFirstChildInParent(false); - springLayout.addSpringView(R.id.primary_widgets_list_view); - springLayout.addSpringView(R.id.work_widgets_list_view); } else { mViewPager = null; - springLayout.addSpringView(R.id.primary_widgets_list_view); } layoutInflater.inflate(R.layout.widgets_full_sheet_search_and_recommendations, springLayout, true); - springLayout.addSpringView(R.id.search_and_recommendations_container); - mSearchAndRecommendationViewHolder = new SearchAndRecommendationViewHolder( findViewById(R.id.search_and_recommendations_container)); mSearchAndRecommendationsScrollController = new SearchAndRecommendationsScrollController( From 3a4ba0bec3b2724534c8b587e2fead05cd3039bd Mon Sep 17 00:00:00 2001 From: Andras Kloczl Date: Mon, 29 Mar 2021 18:47:14 +0200 Subject: [PATCH 11/15] Fix two panel home folder opening display issue Change the rect calculation logic that is used to display an opening folder. If multiple panels are displayed then we calculate the union of the pages. Test: manual Bug: 181962118 Change-Id: I504f22890115ceebc16d60929149fe634bf820d0 --- src/com/android/launcher3/Launcher.java | 4 +--- src/com/android/launcher3/Workspace.java | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 8785fbc2b9..5eba39927f 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1781,9 +1781,7 @@ public class Launcher extends StatefulActivity implements Launche @Override public Rect getFolderBoundingBox() { // We need to bound the folder to the currently visible workspace area - Rect folderBoundingBox = new Rect(); - getWorkspace().getPageAreaRelativeToDragLayer(folderBoundingBox); - return folderBoundingBox; + return getWorkspace().getPageAreaRelativeToDragLayer(); } @Override diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index bd173481b7..48638f59f7 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -2000,16 +2000,26 @@ public class Workspace extends PagedView } /** - * Computes the area relative to dragLayer which is used to display a page. + * Computes and returns the area relative to dragLayer which is used to display a page. + * In case we have multiple pages displayed at the same time, we return the union of the areas. */ - public void getPageAreaRelativeToDragLayer(Rect outArea) { - CellLayout child = (CellLayout) getChildAt(getNextPage()); - if (child == null) { - return; + public Rect getPageAreaRelativeToDragLayer() { + Rect area = new Rect(); + int nextPage = getNextPage(); + int panelCount = getPanelCount(); + for (int page = nextPage; page < nextPage + panelCount; page++) { + CellLayout child = (CellLayout) getChildAt(page); + if (child == null) { + break; + } + + ShortcutAndWidgetContainer boundingLayout = child.getShortcutsAndWidgets(); + Rect tmpRect = new Rect(); + mLauncher.getDragLayer().getDescendantRectRelativeToSelf(boundingLayout, tmpRect); + area.union(tmpRect); } - ShortcutAndWidgetContainer boundingLayout = child.getShortcutsAndWidgets(); - mLauncher.getDragLayer().getDescendantRectRelativeToSelf(boundingLayout, outArea); + return area; } @Override From 1b54846254020aa92e381f7d711b38beda58f1c1 Mon Sep 17 00:00:00 2001 From: vadimt Date: Mon, 29 Mar 2021 14:47:06 -0700 Subject: [PATCH 12/15] Fixing a leak in WallpaperColorInfo Nulling temp listeners after use Test: presubmit Bug: 181356264 Change-Id: I6cace47f1424e2fe59a283bb0e16de523875b6cf --- .../com/android/launcher3/uioverrides/WallpaperColorInfo.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java b/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java index 36c0e342c1..1417995057 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java +++ b/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java @@ -102,9 +102,11 @@ public class WallpaperColorInfo implements OnColorsChangedListener { private void notifyChange() { // Create a new array to avoid concurrent modification when the activity destroys itself. mTempListeners = mListeners.toArray(mTempListeners); - for (OnChangeListener listener : mTempListeners) { + for (int i = mTempListeners.length - 1; i >= 0; --i) { + final OnChangeListener listener = mTempListeners[i]; if (listener != null) { listener.onExtractedColorsChanged(this); + mTempListeners[i] = null; } } } From ec1277eec1f0691fca1ced0eb107f1417a66a1fa Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Thu, 25 Mar 2021 10:41:54 -0400 Subject: [PATCH 13/15] Migrate existing 4x5 and 4x4 grid users to a new 4x5 grid. Due to the dogfood 4x5 grid using the wrong db, there may be some rearranging of items. The goal is to completely remove the old 4x4 and 4x5 grid, but first we need to silently migrate users to the new grid. We still need to keep the old grids in the device profile so we hide them from the Styles & Wallpaper app. We also need to reset and remove the ENABLE_FOUR_COLUMN feature flag from the UI. - Added TODO to remove this logic in the tracking doc Bug: 183965808 Bug: 175329686 Test: have old 4x4 or 4x5 grid set up install apk with these changes confirm that we are now using the new grid and the other grid options are inaccessible to the user Change-Id: I81a91b8415effbe0bf7ba722f11ab44a4169e3df --- res/values/attrs.xml | 3 ++ src/com/android/launcher3/CellLayout.java | 3 +- .../launcher3/InvariantDeviceProfile.java | 4 +++ .../android/launcher3/LauncherAppState.java | 35 +++++++++++++++++-- src/com/android/launcher3/LauncherFiles.java | 2 ++ .../launcher3/config/FeatureFlags.java | 17 ++++++++- .../graphics/GridCustomizationsProvider.java | 5 ++- 7 files changed, 63 insertions(+), 6 deletions(-) diff --git a/res/values/attrs.xml b/res/values/attrs.xml index fc2b4bc5f9..99f6c7584b 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -132,6 +132,9 @@ + + + diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 9df8d44d58..7ece72e4a3 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -19,7 +19,6 @@ package com.android.launcher3; import static android.animation.ValueAnimator.areAnimatorsEnabled; import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5; -import static com.android.launcher3.config.FeatureFlags.ENABLE_FOUR_COLUMNS; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -602,7 +601,7 @@ public class CellLayout extends ViewGroup { if (child instanceof BubbleTextView) { BubbleTextView bubbleChild = (BubbleTextView) child; bubbleChild.setTextVisibility(mContainerType != HOTSEAT); - if (ENABLE_FOUR_COLUMNS.get()) { + if (mActivity.getDeviceProfile().isScalableGrid) { bubbleChild.setCenterVertically(mContainerType != HOTSEAT); } } diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index b0c3bb4e81..754e988da6 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -626,6 +626,8 @@ public class InvariantDeviceProfile { private final boolean isScalable; private final int devicePaddingId; + public final boolean visible; + private final SparseArray extraAttrs; public GridOption(Context context, AttributeSet attrs) { @@ -652,6 +654,8 @@ public class InvariantDeviceProfile { devicePaddingId = a.getResourceId( R.styleable.GridDisplayOption_devicePaddingId, 0); + visible = a.getBoolean(R.styleable.GridDisplayOption_visible, true); + a.recycle(); extraAttrs = Themes.createValueMap(context, attrs, diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 57d76005a6..ccc023ab76 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -17,8 +17,11 @@ package com.android.launcher3; import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS; -import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI; +import static com.android.launcher3.InvariantDeviceProfile.KEY_MIGRATION_SRC_HOTSEAT_COUNT; +import static com.android.launcher3.InvariantDeviceProfile.KEY_MIGRATION_SRC_WORKSPACE_SIZE; +import static com.android.launcher3.config.FeatureFlags.ENABLE_FOUR_COLUMNS; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; +import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI; import android.content.ComponentName; import android.content.Context; @@ -37,10 +40,10 @@ import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.pm.InstallSessionHelper; import com.android.launcher3.pm.InstallSessionTracker; import com.android.launcher3.pm.UserCache; -import com.android.launcher3.util.SettingsCache; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.SafeCloseable; +import com.android.launcher3.util.SettingsCache; import com.android.launcher3.util.SimpleBroadcastReceiver; import com.android.launcher3.widget.custom.CustomWidgetManager; @@ -122,6 +125,34 @@ public class LauncherAppState { mContext = context; mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context); + + // b/175329686 Temporary logic to gracefully migrate group of users to the new 4x5 grid. + String gridName = InvariantDeviceProfile.getCurrentGridName(context); + if (ENABLE_FOUR_COLUMNS.get() + || "reasonable".equals(gridName) + || ENABLE_FOUR_COLUMNS.key.equals(gridName)) { + // Reset flag and remove it from developer options to prevent it from being enabled + // again. + ENABLE_FOUR_COLUMNS.reset(context); + FeatureFlags.removeFlag(ENABLE_FOUR_COLUMNS); + + // Force migration code to run + Utilities.getPrefs(context).edit() + .remove(KEY_MIGRATION_SRC_HOTSEAT_COUNT) + .remove(KEY_MIGRATION_SRC_WORKSPACE_SIZE) + .apply(); + + // We make an empty call here to ensure the database is created with the old IDP grid, + // so that when we set the new grid the migration can proceeds as expected. + LauncherSettings.Settings.call(context.getContentResolver(), ""); + + String newGridName = "practical"; + Utilities.getPrefs(mContext).edit().putString("idp_grid_name", newGridName).commit(); + mInvariantDeviceProfile.setCurrentGrid(context, "practical"); + } else { + FeatureFlags.removeFlag(ENABLE_FOUR_COLUMNS); + } + mIconCache = new IconCache(mContext, mInvariantDeviceProfile, iconCacheFileName); mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache); mModel = new LauncherModel(context, this, mIconCache, new AppFilter(mContext)); diff --git a/src/com/android/launcher3/LauncherFiles.java b/src/com/android/launcher3/LauncherFiles.java index 25afb55472..6c0daa4da9 100644 --- a/src/com/android/launcher3/LauncherFiles.java +++ b/src/com/android/launcher3/LauncherFiles.java @@ -15,6 +15,7 @@ public class LauncherFiles { private static final String XML = ".xml"; public static final String LAUNCHER_DB = "launcher.db"; + public static final String LAUNCHER_4_BY_5_DB = "launcher_4_by_5.db"; public static final String LAUNCHER_4_BY_4_DB = "launcher_4_by_4.db"; public static final String LAUNCHER_3_BY_3_DB = "launcher_3_by_3.db"; public static final String LAUNCHER_2_BY_2_DB = "launcher_2_by_2.db"; @@ -30,6 +31,7 @@ public class LauncherFiles { public static final List ALL_FILES = Collections.unmodifiableList(Arrays.asList( LAUNCHER_DB, + LAUNCHER_4_BY_5_DB, LAUNCHER_4_BY_4_DB, LAUNCHER_3_BY_3_DB, LAUNCHER_2_BY_2_DB, diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index 7f76d27564..51631584a8 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -187,7 +187,7 @@ public final class FeatureFlags { "EXPANDED_SMARTSPACE", false, "Expands smartspace height to two rows. " + "Any apps occupying the first row will be removed from workspace."); - public static final BooleanFlag ENABLE_FOUR_COLUMNS = new DeviceFlag( + public static final DeviceFlag ENABLE_FOUR_COLUMNS = new DeviceFlag( "ENABLE_FOUR_COLUMNS", false, "Uses 4 columns in launcher grid." + "Warning: This will permanently alter your home screen items and is not reversible."); @@ -227,6 +227,12 @@ public final class FeatureFlags { } } + public static void removeFlag(DebugFlag flag) { + synchronized (sDebugFlags) { + sDebugFlags.remove(flag); + } + } + static List getDebugFlags() { synchronized (sDebugFlags) { return new ArrayList<>(sDebugFlags); @@ -304,6 +310,15 @@ public final class FeatureFlags { .getBoolean(key, defaultValue); } + /** + * Resets value to default value. + */ + public void reset(Context context) { + mCurrentValue = defaultValue; + context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE) + .edit().putBoolean(key, defaultValue).apply(); + } + @Override protected StringBuilder appendProps(StringBuilder src) { return super.appendProps(src).append(", mCurrentValue=").append(mCurrentValue); diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java index cb42e7aa05..911f8c3cde 100644 --- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java +++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java @@ -90,7 +90,10 @@ public class GridCustomizationsProvider extends ContentProvider { parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { if ((type == XmlPullParser.START_TAG) && GridOption.TAG_NAME.equals(parser.getName())) { - result.add(new GridOption(getContext(), Xml.asAttributeSet(parser))); + GridOption option = new GridOption(getContext(), Xml.asAttributeSet(parser)); + if (option.visible) { + result.add(option); + } } } } catch (IOException | XmlPullParserException e) { From 04e9f39f19d90ae978660262719f03184501b75e Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 29 Mar 2021 16:21:52 -0700 Subject: [PATCH 14/15] Simplifying all-apps seach pipeline Bug: 183607616 Test: Verified on device Change-Id: Id7ded3c244b747a577cdfcf298db6dddf19fa4eb --- .../uioverrides/QuickstepLauncher.java | 1 - .../launcher3/allapps/SearchUiManager.java | 5 -- .../search/AppsSearchContainerLayout.java | 3 +- .../allapps/search/AppsSearchPipeline.java | 85 ------------------- .../search/DefaultAppSearchAlgorithm.java | 63 +++++++++++--- .../allapps/search/SearchPipeline.java | 37 -------- 6 files changed, 53 insertions(+), 141 deletions(-) delete mode 100644 src/com/android/launcher3/allapps/search/AppsSearchPipeline.java delete mode 100644 src/com/android/launcher3/allapps/search/SearchPipeline.java diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index bae97d763a..b1c04b1e92 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -234,7 +234,6 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { @Override public void onDestroy() { super.onDestroy(); - getAppsView().getSearchUiManager().destroySearch(); mHotseatPredictionController.destroy(); } diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java index 0a2dea99b9..941d3af797 100644 --- a/src/com/android/launcher3/allapps/SearchUiManager.java +++ b/src/com/android/launcher3/allapps/SearchUiManager.java @@ -48,11 +48,6 @@ public interface SearchUiManager { */ float getScrollRangeDelta(Rect insets); - /** - * Called when activity is destroyed. Used to close search system services - */ - default void destroySearch() { } - /** * @return the edit text object */ diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java index bfcc1c75ec..c51bcf5bd4 100644 --- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java +++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java @@ -36,7 +36,6 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.ExtendedEditText; import com.android.launcher3.Insettable; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.allapps.AllAppsContainerView; import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem; @@ -136,7 +135,7 @@ public class AppsSearchContainerLayout extends ExtendedEditText mApps = appsView.getApps(); mAppsView = appsView; mSearchBarController.initialize( - new DefaultAppSearchAlgorithm(mLauncher, LauncherAppState.getInstance(mLauncher)), + new DefaultAppSearchAlgorithm(mLauncher), this, mLauncher, this); } diff --git a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java b/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java deleted file mode 100644 index 42ee4b78be..0000000000 --- a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.allapps.search; - -import android.content.Context; -import android.os.CancellationSignal; - -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem; -import com.android.launcher3.model.AllAppsList; -import com.android.launcher3.model.BaseModelUpdateTask; -import com.android.launcher3.model.BgDataModel; -import com.android.launcher3.model.data.AppInfo; -import com.android.launcher3.search.StringMatcherUtility; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; - -/** - * A device search section for handling app searches - */ -public class AppsSearchPipeline implements SearchPipeline { - - private static final int MAX_RESULTS_COUNT = 5; - - private final LauncherAppState mLauncherAppState; - - public AppsSearchPipeline(Context context, LauncherAppState launcherAppState) { - mLauncherAppState = launcherAppState; - } - - @Override - public void query(String input, Consumer> callback, - CancellationSignal cancellationSignal) { - mLauncherAppState.getModel().enqueueModelUpdateTask(new BaseModelUpdateTask() { - @Override - public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) { - List matchingResults = getTitleMatchResult(apps.data, input); - callback.accept(getAdapterItems(matchingResults)); - } - }); - } - - /** - * Filters {@link AppInfo}s matching specified query - */ - public static ArrayList getTitleMatchResult(List apps, String query) { - // Do an intersection of the words in the query and each title, and filter out all the - // apps that don't match all of the words in the query. - final String queryTextLower = query.toLowerCase(); - final ArrayList result = new ArrayList<>(); - StringMatcherUtility.StringMatcher matcher = - StringMatcherUtility.StringMatcher.getInstance(); - for (AppInfo info : apps) { - if (StringMatcherUtility.matches(queryTextLower, info.title.toString(), matcher)) { - result.add(info); - } - } - return result; - } - - private ArrayList getAdapterItems(List matchingApps) { - ArrayList items = new ArrayList<>(); - for (int i = 0; i < matchingApps.size() && i < MAX_RESULTS_COUNT; i++) { - AdapterItem appItem = AdapterItem.asApp(i, "", matchingApps.get(i), i); - items.add(appItem); - } - - return items; - } -} diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java index a386ef8ee2..1f854c6787 100644 --- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java +++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java @@ -15,25 +15,39 @@ */ package com.android.launcher3.allapps.search; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; + import android.content.Context; import android.os.Handler; +import androidx.annotation.AnyThread; + import com.android.launcher3.LauncherAppState; import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem; +import com.android.launcher3.model.AllAppsList; +import com.android.launcher3.model.BaseModelUpdateTask; +import com.android.launcher3.model.BgDataModel; +import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.search.SearchAlgorithm; import com.android.launcher3.search.SearchCallback; +import com.android.launcher3.search.StringMatcherUtility; + +import java.util.ArrayList; +import java.util.List; /** * The default search implementation. */ public class DefaultAppSearchAlgorithm implements SearchAlgorithm { - protected final Handler mResultHandler; - private final AppsSearchPipeline mAppsSearchPipeline; + private static final int MAX_RESULTS_COUNT = 5; - public DefaultAppSearchAlgorithm(Context context, LauncherAppState launcherAppState) { - mResultHandler = new Handler(); - mAppsSearchPipeline = new AppsSearchPipeline(context, launcherAppState); + private final LauncherAppState mAppState; + private final Handler mResultHandler; + + public DefaultAppSearchAlgorithm(Context context) { + mAppState = LauncherAppState.getInstance(context); + mResultHandler = new Handler(MAIN_EXECUTOR.getLooper()); } @Override @@ -44,11 +58,38 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm { } @Override - public void doSearch(final String query, - final SearchCallback callback) { - mAppsSearchPipeline.query(query, - results -> mResultHandler.post( - () -> callback.onSearchResult(query, results)), - null); + public void doSearch(String query, SearchCallback callback) { + mAppState.getModel().enqueueModelUpdateTask(new BaseModelUpdateTask() { + @Override + public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) { + ArrayList result = getTitleMatchResult(apps.data, query); + mResultHandler.post(() -> callback.onSearchResult(query, result)); + } + }); + } + + /** + * Filters {@link AppInfo}s matching specified query + */ + @AnyThread + public static ArrayList getTitleMatchResult(List apps, String query) { + // Do an intersection of the words in the query and each title, and filter out all the + // apps that don't match all of the words in the query. + final String queryTextLower = query.toLowerCase(); + final ArrayList result = new ArrayList<>(); + StringMatcherUtility.StringMatcher matcher = + StringMatcherUtility.StringMatcher.getInstance(); + + int resultCount = 0; + int total = apps.size(); + for (int i = 0; i < total && resultCount < MAX_RESULTS_COUNT; i++) { + AppInfo info = apps.get(i); + if (StringMatcherUtility.matches(queryTextLower, info.title.toString(), matcher)) { + AdapterItem appItem = AdapterItem.asApp(resultCount, "", info, resultCount); + result.add(appItem); + resultCount++; + } + } + return result; } } diff --git a/src/com/android/launcher3/allapps/search/SearchPipeline.java b/src/com/android/launcher3/allapps/search/SearchPipeline.java deleted file mode 100644 index 3516a41724..0000000000 --- a/src/com/android/launcher3/allapps/search/SearchPipeline.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.allapps.search; - -import android.os.CancellationSignal; - -import com.android.launcher3.allapps.AllAppsGridAdapter; - -import java.util.ArrayList; -import java.util.function.Consumer; - -/** - * An interface for handling search within pipeline - */ -// Remove when System Service API is added. -public interface SearchPipeline { - - /** - * Perform query - */ - void query(String input, - Consumer> callback, - CancellationSignal cancellationSignal); -} From 8ffdc4b6c4ae7f3fe10cd6e25a007c22fcbdeb99 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Tue, 30 Mar 2021 16:37:21 +0000 Subject: [PATCH 15/15] Revert "Enable device search" This reverts commit 6323aa270cd807651eb681120b03fbaabf058264. Reason for revert: 4 tests failing in tapl Bug: 184030316 Bug: 184030696 Bug: 184030463 Bug: 184030324 Change-Id: Ib5daebbca9bad4eefd20ca51755f5a02a9c4f6aa --- src/com/android/launcher3/config/FeatureFlags.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index 6daecba1a8..96251f000c 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -93,7 +93,7 @@ public final class FeatureFlags { public static final BooleanFlag ENABLE_DEVICE_SEARCH = new DeviceFlag( - "ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps"); + "ENABLE_DEVICE_SEARCH", false, "Allows on device search in all apps"); public static final BooleanFlag FOLDER_NAME_SUGGEST = new DeviceFlag( "FOLDER_NAME_SUGGEST", true,