From 0fc3d1275a2e6a68b276b47032b696b8f7622016 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 11 Aug 2020 18:49:28 -0700 Subject: [PATCH 01/12] Moving hotseat predictions to ModelDelegate Bug: 160748731 Change-Id: I8db7856a17e0b6ca45b4d5ec3513f788f22db11a --- quickstep/res/values/override.xml | 2 - .../launcher3/BaseQuickstepLauncher.java | 17 - .../appprediction/ComponentKeyMapper.java | 63 --- .../appprediction/DynamicItemCache.java | 268 ------------- .../hybridhotseat/HotseatEduController.java | 14 +- .../HotseatPredictionController.java | 376 +++--------------- .../hybridhotseat/HotseatPredictionModel.java | 66 ++- .../hybridhotseat/HotseatRestoreHelper.java | 29 +- .../launcher3/model/AppEventProducer.java | 103 ++++- .../model/QuickstepModelDelegate.java | 52 ++- .../uioverrides/QuickstepLauncher.java | 57 +-- .../util/QuickstepOnboardingPrefs.java | 6 +- res/values/config.xml | 1 - src/com/android/launcher3/DropTarget.java | 12 - src/com/android/launcher3/Launcher.java | 14 - .../android/launcher3/LauncherAppState.java | 7 - src/com/android/launcher3/LauncherModel.java | 7 + src/com/android/launcher3/Workspace.java | 3 +- src/com/android/launcher3/folder/Folder.java | 4 +- .../graphics/LauncherPreviewRenderer.java | 35 +- .../launcher3/logging/StatsLogManager.java | 8 +- .../launcher3/model/BaseLoaderResults.java | 9 - .../android/launcher3/model/BgDataModel.java | 10 - .../android/launcher3/model/LoaderTask.java | 30 +- .../launcher3/model/ModelDelegate.java | 6 + .../launcher3/model/PredictionModel.java | 136 ------- .../SecondaryDisplayLauncher.java | 3 - .../launcher3/util/OnboardingPrefs.java | 3 +- 28 files changed, 293 insertions(+), 1048 deletions(-) delete mode 100644 quickstep/src/com/android/launcher3/appprediction/ComponentKeyMapper.java delete mode 100644 quickstep/src/com/android/launcher3/appprediction/DynamicItemCache.java delete mode 100644 src/com/android/launcher3/model/PredictionModel.java diff --git a/quickstep/res/values/override.xml b/quickstep/res/values/override.xml index 397ea82489..8f4ce4343b 100644 --- a/quickstep/res/values/override.xml +++ b/quickstep/res/values/override.xml @@ -27,8 +27,6 @@ com.android.quickstep.logging.UserEventDispatcherExtension - com.android.launcher3.hybridhotseat.HotseatPredictionModel - com.android.launcher3.model.QuickstepModelDelegate diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index a0016cb905..68111d2632 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -26,12 +26,10 @@ import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.content.Intent; import android.content.IntentSender; -import android.content.SharedPreferences; import android.os.Bundle; import android.os.CancellationSignal; import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.model.WellbeingModel; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.proxy.ProxyActivityStarter; @@ -40,14 +38,12 @@ import com.android.launcher3.statehandlers.BackButtonAlphaHandler; import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.uioverrides.RecentsViewStateController; -import com.android.launcher3.util.OnboardingPrefs; import com.android.launcher3.util.UiThreadHelper; import com.android.quickstep.RecentsModel; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener; import com.android.quickstep.SystemUiProxy; -import com.android.quickstep.util.QuickstepOnboardingPrefs; import com.android.quickstep.util.RemoteAnimationProvider; import com.android.quickstep.util.RemoteFadeOutAnimationListener; import com.android.quickstep.views.OverviewActionsView; @@ -73,7 +69,6 @@ public abstract class BaseQuickstepLauncher extends Launcher Float.intBitsToFloat(arg1), arg2 != 0); private OverviewActionsView mActionsView; - protected HotseatPredictionController mHotseatPredictionController; @Override protected void onCreate(Bundle savedInstanceState) { @@ -221,11 +216,6 @@ public abstract class BaseQuickstepLauncher extends Launcher return mDepthController; } - @Override - protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) { - return new QuickstepOnboardingPrefs(this, sharedPrefs); - } - @Override public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) { QuickstepAppTransitionManagerImpl appTransitionManager = @@ -314,13 +304,6 @@ public abstract class BaseQuickstepLauncher extends Launcher Stream.of(WellbeingModel.SHORTCUT_FACTORY)); } - /** - * Returns Prediction controller for hybrid hotseat - */ - public HotseatPredictionController getHotseatPredictionController() { - return mHotseatPredictionController; - } - public void setHintUserWillBeActive() { addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE); } diff --git a/quickstep/src/com/android/launcher3/appprediction/ComponentKeyMapper.java b/quickstep/src/com/android/launcher3/appprediction/ComponentKeyMapper.java deleted file mode 100644 index d200868899..0000000000 --- a/quickstep/src/com/android/launcher3/appprediction/ComponentKeyMapper.java +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (C) 2019 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.appprediction; - -import static com.android.quickstep.InstantAppResolverImpl.COMPONENT_CLASS_MARKER; - -import com.android.launcher3.allapps.AllAppsStore; -import com.android.launcher3.model.data.AppInfo; -import com.android.launcher3.model.data.ItemInfoWithIcon; -import com.android.launcher3.util.ComponentKey; - -public class ComponentKeyMapper { - - protected final ComponentKey componentKey; - private final DynamicItemCache mCache; - - public ComponentKeyMapper(ComponentKey key, DynamicItemCache cache) { - componentKey = key; - mCache = cache; - } - - public String getPackage() { - return componentKey.componentName.getPackageName(); - } - - public String getComponentClass() { - return componentKey.componentName.getClassName(); - } - - public ComponentKey getComponentKey() { - return componentKey; - } - - @Override - public String toString() { - return componentKey.toString(); - } - - public ItemInfoWithIcon getApp(AllAppsStore store) { - AppInfo item = store.getApp(componentKey); - if (item != null) { - return item; - } else if (getComponentClass().equals(COMPONENT_CLASS_MARKER)) { - return mCache.getInstantApp(componentKey.componentName.getPackageName()); - } else { - return mCache.getShortcutInfo(componentKey); - } - } -} diff --git a/quickstep/src/com/android/launcher3/appprediction/DynamicItemCache.java b/quickstep/src/com/android/launcher3/appprediction/DynamicItemCache.java deleted file mode 100644 index ab96b1340a..0000000000 --- a/quickstep/src/com/android/launcher3/appprediction/DynamicItemCache.java +++ /dev/null @@ -1,268 +0,0 @@ -/** - * Copyright (C) 2019 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.appprediction; - -import static android.content.pm.PackageManager.MATCH_INSTANT; - -import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; -import static com.android.quickstep.InstantAppResolverImpl.COMPONENT_CLASS_MARKER; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.ShortcutInfo; -import android.net.Uri; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.util.ArrayMap; -import android.util.Log; - -import androidx.annotation.MainThread; -import androidx.annotation.Nullable; -import androidx.annotation.UiThread; -import androidx.annotation.WorkerThread; - -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.allapps.AllAppsStore; -import com.android.launcher3.icons.IconCache; -import com.android.launcher3.model.data.AppInfo; -import com.android.launcher3.model.data.WorkspaceItemInfo; -import com.android.launcher3.shortcuts.ShortcutKey; -import com.android.launcher3.shortcuts.ShortcutRequest; -import com.android.launcher3.util.ComponentKey; -import com.android.launcher3.util.InstantAppResolver; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Utility class which loads and caches predicted items like instant apps and shortcuts, before - * they can be displayed on the UI - */ -public class DynamicItemCache { - - private static final String TAG = "DynamicItemCache"; - private static final boolean DEBUG = false; - private static final String DEFAULT_URL = "default-url"; - - private static final int BG_MSG_LOAD_SHORTCUTS = 1; - private static final int BG_MSG_LOAD_INSTANT_APPS = 2; - - private static final int UI_MSG_UPDATE_SHORTCUTS = 1; - private static final int UI_MSG_UPDATE_INSTANT_APPS = 2; - - private final Context mContext; - private final Handler mWorker; - private final Handler mUiHandler; - private final InstantAppResolver mInstantAppResolver; - private final Runnable mOnUpdateCallback; - private final IconCache mIconCache; - - private final Map mShortcuts; - private final Map mInstantApps; - - public DynamicItemCache(Context context, Runnable onUpdateCallback) { - mContext = context; - mWorker = new Handler(MODEL_EXECUTOR.getLooper(), this::handleWorkerMessage); - mUiHandler = new Handler(Looper.getMainLooper(), this::handleUiMessage); - mInstantAppResolver = InstantAppResolver.newInstance(context); - mOnUpdateCallback = onUpdateCallback; - mIconCache = LauncherAppState.getInstance(mContext).getIconCache(); - - mShortcuts = new HashMap<>(); - mInstantApps = new HashMap<>(); - } - - public void cacheItems(List shortcutKeys, List pkgNames) { - if (!shortcutKeys.isEmpty()) { - mWorker.removeMessages(BG_MSG_LOAD_SHORTCUTS); - Message.obtain(mWorker, BG_MSG_LOAD_SHORTCUTS, shortcutKeys).sendToTarget(); - } - if (!pkgNames.isEmpty()) { - mWorker.removeMessages(BG_MSG_LOAD_INSTANT_APPS); - Message.obtain(mWorker, BG_MSG_LOAD_INSTANT_APPS, pkgNames).sendToTarget(); - } - } - - private boolean handleWorkerMessage(Message msg) { - switch (msg.what) { - case BG_MSG_LOAD_SHORTCUTS: { - List shortcutKeys = msg.obj != null ? - (List) msg.obj : Collections.EMPTY_LIST; - Map shortcutKeyAndInfos = new ArrayMap<>(); - for (ShortcutKey shortcutKey : shortcutKeys) { - WorkspaceItemInfo workspaceItemInfo = loadShortcutWorker(shortcutKey); - if (workspaceItemInfo != null) { - shortcutKeyAndInfos.put(shortcutKey, workspaceItemInfo); - } - } - Message.obtain(mUiHandler, UI_MSG_UPDATE_SHORTCUTS, shortcutKeyAndInfos) - .sendToTarget(); - return true; - } - case BG_MSG_LOAD_INSTANT_APPS: { - List pkgNames = msg.obj != null ? - (List) msg.obj : Collections.EMPTY_LIST; - List instantAppItemInfos = new ArrayList<>(); - for (String pkgName : pkgNames) { - InstantAppItemInfo instantAppItemInfo = loadInstantApp(pkgName); - if (instantAppItemInfo != null) { - instantAppItemInfos.add(instantAppItemInfo); - } - } - Message.obtain(mUiHandler, UI_MSG_UPDATE_INSTANT_APPS, instantAppItemInfos) - .sendToTarget(); - return true; - } - } - - return false; - } - - private boolean handleUiMessage(Message msg) { - switch (msg.what) { - case UI_MSG_UPDATE_SHORTCUTS: { - mShortcuts.clear(); - mShortcuts.putAll((Map) msg.obj); - mOnUpdateCallback.run(); - return true; - } - case UI_MSG_UPDATE_INSTANT_APPS: { - List instantAppItemInfos = (List) msg.obj; - mInstantApps.clear(); - for (InstantAppItemInfo instantAppItemInfo : instantAppItemInfos) { - mInstantApps.put(instantAppItemInfo.getTargetComponent().getPackageName(), - instantAppItemInfo); - } - mOnUpdateCallback.run(); - if (DEBUG) { - Log.d(TAG, String.format("Cache size: %d, Cache: %s", - mInstantApps.size(), mInstantApps.toString())); - } - return true; - } - } - - return false; - } - - @WorkerThread - private WorkspaceItemInfo loadShortcutWorker(ShortcutKey shortcutKey) { - List details = shortcutKey.buildRequest(mContext).query(ShortcutRequest.ALL); - if (!details.isEmpty()) { - WorkspaceItemInfo si = new WorkspaceItemInfo(details.get(0), mContext); - mIconCache.getShortcutIcon(si, details.get(0)); - return si; - } - if (DEBUG) { - Log.d(TAG, "No shortcut found: " + shortcutKey.toString()); - } - return null; - } - - private InstantAppItemInfo loadInstantApp(String pkgName) { - PackageManager pm = mContext.getPackageManager(); - - try { - ApplicationInfo ai = pm.getApplicationInfo(pkgName, 0); - if (!mInstantAppResolver.isInstantApp(ai)) { - return null; - } - } catch (PackageManager.NameNotFoundException e) { - return null; - } - - String url = retrieveDefaultUrl(pkgName, pm); - if (url == null) { - Log.w(TAG, "no default-url available for pkg " + pkgName); - return null; - } - - Intent intent = new Intent(Intent.ACTION_VIEW) - .addCategory(Intent.CATEGORY_BROWSABLE) - .setData(Uri.parse(url)); - InstantAppItemInfo info = new InstantAppItemInfo(intent, pkgName); - IconCache iconCache = LauncherAppState.getInstance(mContext).getIconCache(); - iconCache.getTitleAndIcon(info, false); - if (info.bitmap.icon == null || iconCache.isDefaultIcon(info.bitmap, info.user)) { - return null; - } - return info; - } - - @Nullable - public static String retrieveDefaultUrl(String pkgName, PackageManager pm) { - Intent mainIntent = new Intent().setAction(Intent.ACTION_MAIN) - .addCategory(Intent.CATEGORY_LAUNCHER).setPackage(pkgName); - List resolveInfos = pm.queryIntentActivities( - mainIntent, MATCH_INSTANT | PackageManager.GET_META_DATA); - String url = null; - for (ResolveInfo resolveInfo : resolveInfos) { - if (resolveInfo.activityInfo.metaData != null - && resolveInfo.activityInfo.metaData.containsKey(DEFAULT_URL)) { - url = resolveInfo.activityInfo.metaData.getString(DEFAULT_URL); - } - } - return url; - } - - @UiThread - public InstantAppItemInfo getInstantApp(String pkgName) { - return mInstantApps.get(pkgName); - } - - @MainThread - public WorkspaceItemInfo getShortcutInfo(ComponentKey key) { - return mShortcuts.get(key); - } - - /** - * requests and caches icons for app targets - */ - public void updateDependencies(List componentKeyMappers, - AllAppsStore appsStore, IconCache.ItemInfoUpdateReceiver callback, int itemCount) { - List instantAppsToLoad = new ArrayList<>(); - List shortcutsToLoad = new ArrayList<>(); - int total = componentKeyMappers.size(); - for (int i = 0, count = 0; i < total && count < itemCount; i++) { - ComponentKeyMapper mapper = componentKeyMappers.get(i); - // Update instant apps - if (COMPONENT_CLASS_MARKER.equals(mapper.getComponentClass())) { - instantAppsToLoad.add(mapper.getPackage()); - count++; - } else if (mapper.getComponentKey() instanceof ShortcutKey) { - shortcutsToLoad.add((ShortcutKey) mapper.getComponentKey()); - count++; - } else { - // Reload high res icon - AppInfo info = (AppInfo) mapper.getApp(appsStore); - if (info != null) { - if (info.usingLowResIcon()) { - mIconCache.updateIconInBackground(callback, info); - } - count++; - } - } - } - cacheItems(shortcutsToLoad, instantAppsToLoad); - } -} diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java index 8ebf1251ec..4451e7a6c1 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java @@ -47,35 +47,27 @@ import java.util.stream.IntStream; */ public class HotseatEduController { - public static final String HOTSEAT_EDU_ACTION = - "com.android.launcher3.action.SHOW_HYBRID_HOTSEAT_EDU"; public static final String SETTINGS_ACTION = "android.settings.ACTION_CONTENT_SUGGESTIONS_SETTINGS"; private final Launcher mLauncher; private final Hotseat mHotseat; - private HotseatRestoreHelper mRestoreHelper; private List mPredictedApps; private HotseatEduDialog mActiveDialog; private ArrayList mNewItems = new ArrayList<>(); private IntArray mNewScreens = null; - private Runnable mOnOnboardingComplete; - HotseatEduController(Launcher launcher, HotseatRestoreHelper restoreHelper, Runnable runnable) { + HotseatEduController(Launcher launcher) { mLauncher = launcher; mHotseat = launcher.getHotseat(); - mRestoreHelper = restoreHelper; - mOnOnboardingComplete = runnable; } /** * Checks what type of migration should be used and migrates hotseat */ void migrate() { - if (mRestoreHelper != null) { - mRestoreHelper.createBackup(); - } + HotseatRestoreHelper.createBackup(mLauncher); if (FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get()) { migrateToFolder(); } else { @@ -227,7 +219,7 @@ public class HotseatEduController { } void finishOnboarding() { - mOnOnboardingComplete.run(); + mLauncher.getModel().onWorkspaceUiChanged(); } void showDimissTip() { diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index b94e6337d0..6fe16c9faa 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -15,23 +15,17 @@ */ package com.android.launcher3.hybridhotseat; -import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.hybridhotseat.HotseatEduController.getSettingsIntent; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_PREDICTION_PINNED; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_RANKED; import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; -import android.app.prediction.AppPredictionContext; -import android.app.prediction.AppPredictionManager; -import android.app.prediction.AppPredictor; -import android.app.prediction.AppTarget; -import android.app.prediction.AppTargetEvent; import android.content.ComponentName; import android.os.Process; -import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.View; import android.view.ViewGroup; @@ -44,77 +38,51 @@ import com.android.launcher3.DropTarget; import com.android.launcher3.Hotseat; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.allapps.AllAppsStore; import com.android.launcher3.anim.AnimationSuccessListener; -import com.android.launcher3.appprediction.ComponentKeyMapper; -import com.android.launcher3.appprediction.DynamicItemCache; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; -import com.android.launcher3.icons.IconCache; +import com.android.launcher3.graphics.DragPreviewProvider; import com.android.launcher3.logger.LauncherAtom.ContainerInfo; import com.android.launcher3.logger.LauncherAtom.PredictedHotseatContainer; import com.android.launcher3.logging.InstanceId; -import com.android.launcher3.model.data.AppInfo; -import com.android.launcher3.model.data.FolderInfo; +import com.android.launcher3.model.BgDataModel.FixedContainerItems; import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.SystemShortcut; -import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.uioverrides.PredictedAppIcon; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.userevent.nano.LauncherLogProto; -import com.android.launcher3.util.ComponentKey; -import com.android.launcher3.util.IntArray; import com.android.launcher3.util.OnboardingPrefs; import com.android.launcher3.views.ArrowTipView; import com.android.launcher3.views.Snackbar; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.OptionalInt; -import java.util.stream.IntStream; +import java.util.stream.Collectors; /** * Provides prediction ability for the hotseat. Fills gaps in hotseat with predicted items, allows * pinning of predicted apps and manages replacement of predicted apps with user drag. */ public class HotseatPredictionController implements DragController.DragListener, - View.OnAttachStateChangeListener, SystemShortcut.Factory, - InvariantDeviceProfile.OnIDPChangeListener, AllAppsStore.OnUpdateListener, - IconCache.ItemInfoUpdateReceiver, DragSource { + SystemShortcut.Factory, InvariantDeviceProfile.OnIDPChangeListener, + DragSource { - private static final String TAG = "PredictiveHotseat"; - private static final boolean DEBUG = false; - - private static final String PREDICTION_CLIENT = "hotseat"; - private DropTarget.DragObject mDragObject; private int mHotSeatItemsCount; - private int mPredictedSpotsCount = 0; private Launcher mLauncher; private final Hotseat mHotseat; - private final HotseatRestoreHelper mRestoreHelper; + private List mPredictedItems = Collections.emptyList(); - private List mComponentKeyMappers = new ArrayList<>(); - - private DynamicItemCache mDynamicItemCache; - - private final HotseatPredictionModel mPredictionModel; - private AppPredictor mAppPredictor; - private AllAppsStore mAllAppsStore; private AnimatorSet mIconRemoveAnimators; private boolean mUIUpdatePaused = false; - private boolean mIsDestroyed = false; - + private boolean mDragInProgress = false; private List mOutlineDrawings = new ArrayList<>(); @@ -130,26 +98,23 @@ public class HotseatPredictionController implements DragController.DragListener, mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); return true; } + // Start the drag - mLauncher.getWorkspace().beginDragShared(v, this, new DragOptions()); + // Use a new itemInfo so that the original predicted item is stable + WorkspaceItemInfo dragItem = new WorkspaceItemInfo((WorkspaceItemInfo) v.getTag()); + v.setVisibility(View.INVISIBLE); + mLauncher.getWorkspace().beginDragShared( + v, null, this, dragItem, new DragPreviewProvider(v), new DragOptions()); return true; }; public HotseatPredictionController(Launcher launcher) { mLauncher = launcher; mHotseat = launcher.getHotseat(); - mAllAppsStore = mLauncher.getAppsView().getAppsStore(); - LauncherAppState appState = LauncherAppState.getInstance(launcher); - mPredictionModel = (HotseatPredictionModel) appState.getPredictionModel(); - mAllAppsStore.addUpdateListener(this); - mDynamicItemCache = new DynamicItemCache(mLauncher, this::fillGapsWithPrediction); mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons; + mLauncher.getDragController().addDragListener(this); + launcher.getDeviceProfile().inv.addOnChangeListener(this); - mHotseat.addOnAttachStateChangeListener(this); - mRestoreHelper = new HotseatRestoreHelper(mLauncher); - if (mHotseat.isAttachedToWindow()) { - onViewAttachedToWindow(mHotseat); - } } /** @@ -157,7 +122,7 @@ public class HotseatPredictionController implements DragController.DragListener, */ public void showEdu() { mLauncher.getStateManager().goToState(NORMAL, true, () -> { - if (mComponentKeyMappers.isEmpty()) { + if (mPredictedItems.isEmpty()) { // launcher has empty predictions set Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_disabled, R.string.hotseat_prediction_settings, null, @@ -165,10 +130,10 @@ public class HotseatPredictionController implements DragController.DragListener, } else if (getPredictedIcons().size() >= (mHotSeatItemsCount + 1) / 2) { showDiscoveryTip(); } else { - HotseatEduController eduController = new HotseatEduController(mLauncher, - mRestoreHelper, - this::createPredictor); - eduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers)); + HotseatEduController eduController = new HotseatEduController(mLauncher); + eduController.setPredictedApps(mPredictedItems.stream() + .map(i -> (WorkspaceItemInfo) i) + .collect(Collectors.toList())); eduController.showEdu(); } }); @@ -192,17 +157,7 @@ public class HotseatPredictionController implements DragController.DragListener, * Returns if hotseat client has predictions */ public boolean hasPredictions() { - return !mComponentKeyMappers.isEmpty(); - } - - @Override - public void onViewAttachedToWindow(View view) { - mLauncher.getDragController().addDragListener(this); - } - - @Override - public void onViewDetachedFromWindow(View view) { - mLauncher.getDragController().removeDragListener(this); + return !mPredictedItems.isEmpty(); } private void fillGapsWithPrediction() { @@ -210,15 +165,10 @@ public class HotseatPredictionController implements DragController.DragListener, } private void fillGapsWithPrediction(boolean animate, Runnable callback) { - if (mUIUpdatePaused || mDragObject != null) { - return; - } - List predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers); - if (mComponentKeyMappers.isEmpty() != predictedApps.isEmpty()) { - // Safely ignore update as AppsList is not ready yet. This will called again once - // apps are ready (HotseatPredictionController#onAppsUpdated) + if (mUIUpdatePaused || mDragInProgress) { return; } + int predictionIndex = 0; ArrayList newItems = new ArrayList<>(); // make sure predicted icon removal and filling predictions don't step on each other @@ -240,14 +190,15 @@ public class HotseatPredictionController implements DragController.DragListener, if (child != null && !isPredictedIcon(child)) { continue; } - if (predictedApps.size() <= predictionIndex) { + if (mPredictedItems.size() <= predictionIndex) { // Remove predicted apps from the past if (isPredictedIcon(child)) { mHotseat.removeView(child); } continue; } - WorkspaceItemInfo predictedItem = predictedApps.get(predictionIndex++); + WorkspaceItemInfo predictedItem = + (WorkspaceItemInfo) mPredictedItems.get(predictionIndex++); if (isPredictedIcon(child) && child.isEnabled()) { PredictedAppIcon icon = (PredictedAppIcon) child; icon.applyFromWorkspaceItem(predictedItem); @@ -257,7 +208,6 @@ public class HotseatPredictionController implements DragController.DragListener, } preparePredictionInfo(predictedItem, rank); } - mPredictedSpotsCount = predictionIndex; bindItems(newItems, animate, callback); } @@ -285,13 +235,7 @@ public class HotseatPredictionController implements DragController.DragListener, * Unregisters callbacks and frees resources */ public void destroy() { - mIsDestroyed = true; - mAllAppsStore.removeUpdateListener(this); mLauncher.getDeviceProfile().inv.removeOnChangeListener(this); - mHotseat.removeOnAttachStateChangeListener(this); - if (mAppPredictor != null) { - mAppPredictor.destroy(); - } } /** @@ -305,97 +249,14 @@ public class HotseatPredictionController implements DragController.DragListener, } /** - * Creates App Predictor with all the current apps pinned on the hotseat + * Sets or updates the predicted items */ - public void createPredictor() { - AppPredictionManager apm = mLauncher.getSystemService(AppPredictionManager.class); - if (apm == null) { - return; + public void setPredictedItems(FixedContainerItems items) { + mPredictedItems = items.items; + if (mPredictedItems.isEmpty()) { + HotseatRestoreHelper.restoreBackup(mLauncher); } - if (mAppPredictor != null) { - mAppPredictor.destroy(); - mAppPredictor = null; - } - WeakReference controllerRef = new WeakReference<>(this); - - - mPredictionModel.createBundle(bundle -> { - if (mIsDestroyed) return; - mAppPredictor = apm.createAppPredictionSession( - new AppPredictionContext.Builder(mLauncher) - .setUiSurface(PREDICTION_CLIENT) - .setPredictedTargetCount(mHotSeatItemsCount) - .setExtras(bundle) - .build()); - mAppPredictor.registerPredictionUpdates( - mLauncher.getApplicationContext().getMainExecutor(), - list -> { - if (controllerRef.get() != null) { - controllerRef.get().setPredictedApps(list); - } - }); - mAppPredictor.requestPredictionUpdate(); - }); - setPauseUIUpdate(false); - } - - /** - * Create WorkspaceItemInfo objects and binds PredictedAppIcon views for cached predicted items. - */ - public void showCachedItems(List apps, IntArray ranks) { - if (hasPredictions() && mAppPredictor != null) { - mAppPredictor.requestPredictionUpdate(); - fillGapsWithPrediction(); - return; - } - int count = Math.min(ranks.size(), apps.size()); - List items = new ArrayList<>(count); - for (int i = 0; i < count; i++) { - WorkspaceItemInfo item = new WorkspaceItemInfo(apps.get(i)); - ComponentKey componentKey = new ComponentKey(item.getTargetComponent(), item.user); - preparePredictionInfo(item, ranks.get(i)); - items.add(item); - - mComponentKeyMappers.add(new ComponentKeyMapper(componentKey, mDynamicItemCache)); - } - updateDependencies(); - bindItems(items, false, null); - } - - private void setPredictedApps(List appTargets) { - mComponentKeyMappers.clear(); - if (appTargets.isEmpty()) { - mRestoreHelper.restoreBackup(); - } - StringBuilder predictionLog = new StringBuilder("predictedApps: [\n"); - ArrayList componentKeys = new ArrayList<>(); - for (AppTarget appTarget : appTargets) { - ComponentKey key; - if (appTarget.getShortcutInfo() != null) { - key = ShortcutKey.fromInfo(appTarget.getShortcutInfo()); - } else { - key = new ComponentKey(new ComponentName(appTarget.getPackageName(), - appTarget.getClassName()), appTarget.getUser()); - } - componentKeys.add(key); - predictionLog.append(key.toString()); - predictionLog.append(",rank:"); - predictionLog.append(appTarget.getRank()); - predictionLog.append("\n"); - mComponentKeyMappers.add(new ComponentKeyMapper(key, mDynamicItemCache)); - } - predictionLog.append("]"); - if (Utilities.IS_DEBUG_DEVICE) { - HotseatFileLog.INSTANCE.get(mLauncher).log(TAG, predictionLog.toString()); - } - updateDependencies(); fillGapsWithPrediction(); - mPredictionModel.cachePredictionComponentKeys(componentKeys); - } - - private void updateDependencies() { - mDynamicItemCache.updateDependencies(mComponentKeyMappers, mAllAppsStore, this, - mHotSeatItemsCount); } /** @@ -414,42 +275,9 @@ public class HotseatPredictionController implements DragController.DragListener, workspaceItemInfo.cellX, workspaceItemInfo.cellY); ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 1, 0.8f, 1).start(); icon.pin(workspaceItemInfo); - AppTarget appTarget = mPredictionModel.getAppTargetFromInfo(workspaceItemInfo); - if (appTarget != null) { - notifyItemAction(mPredictionModel.wrapAppTargetWithLocation(appTarget, - AppTargetEvent.ACTION_PIN, workspaceItemInfo)); - } - } - - private List mapToWorkspaceItemInfo( - List components) { - AllAppsStore allAppsStore = mLauncher.getAppsView().getAppsStore(); - if (allAppsStore.getApps().length == 0) { - return Collections.emptyList(); - } - - List predictedApps = new ArrayList<>(); - for (ComponentKeyMapper mapper : components) { - ItemInfoWithIcon info = mapper.getApp(allAppsStore); - if (info instanceof AppInfo) { - WorkspaceItemInfo predictedApp = new WorkspaceItemInfo((AppInfo) info); - predictedApp.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; - predictedApps.add(predictedApp); - } else if (info instanceof WorkspaceItemInfo) { - WorkspaceItemInfo predictedApp = new WorkspaceItemInfo((WorkspaceItemInfo) info); - predictedApp.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; - predictedApps.add(predictedApp); - } else { - if (DEBUG) { - Log.e(TAG, "Predicted app not found: " + mapper); - } - } - // Stop at the number of hotseat items - if (predictedApps.size() == mHotSeatItemsCount) { - break; - } - } - return predictedApps; + mLauncher.getStatsLogManager().logger() + .withItemInfo(workspaceItemInfo) + .log(LAUNCHER_HOTSEAT_PREDICTION_PINNED); } private List getPredictedIcons() { @@ -465,7 +293,7 @@ public class HotseatPredictionController implements DragController.DragListener, } private void removePredictedApps(List outlines, - ItemInfo draggedInfo) { + DropTarget.DragObject dragObject) { if (mIconRemoveAnimators != null) { mIconRemoveAnimators.end(); } @@ -475,7 +303,7 @@ public class HotseatPredictionController implements DragController.DragListener, if (!icon.isEnabled()) { continue; } - if (icon.getTag().equals(draggedInfo)) { + if (dragObject.dragSource == this && icon.equals(dragObject.originalView)) { mHotseat.removeView(icon); continue; } @@ -497,84 +325,23 @@ public class HotseatPredictionController implements DragController.DragListener, mIconRemoveAnimators.start(); } - private void notifyItemAction(AppTargetEvent event) { - if (mAppPredictor != null) { - mAppPredictor.notifyAppTargetEvent(event); - } - } - @Override public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { - removePredictedApps(mOutlineDrawings, dragObject.dragInfo); - mDragObject = dragObject; + removePredictedApps(mOutlineDrawings, dragObject); if (mOutlineDrawings.isEmpty()) return; for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) { mHotseat.addDelegatedCellDrawing(outlineDrawing); } + mDragInProgress = true; mHotseat.invalidate(); } - /** - * Unpins pinned app when it's converted into a folder - */ - public void folderCreatedFromWorkspaceItem(ItemInfo itemInfo, FolderInfo folderInfo) { - AppTarget folderTarget = mPredictionModel.getAppTargetFromInfo(folderInfo); - AppTarget itemTarget = mPredictionModel.getAppTargetFromInfo(itemInfo); - if (folderTarget != null && HotseatPredictionModel.isTrackedForPrediction(folderInfo)) { - notifyItemAction(mPredictionModel.wrapAppTargetWithLocation(folderTarget, - AppTargetEvent.ACTION_PIN, folderInfo)); - } - // using folder info with isTrackedForPrediction as itemInfo.container is already changed - // to folder by this point - if (itemTarget != null && HotseatPredictionModel.isTrackedForPrediction(folderInfo)) { - notifyItemAction(mPredictionModel.wrapAppTargetWithLocation(itemTarget, - AppTargetEvent.ACTION_UNPIN, folderInfo - )); - } - } - - /** - * Pins workspace item created when all folder items are removed but one - */ - public void folderConvertedToWorkspaceItem(ItemInfo itemInfo, FolderInfo folderInfo) { - AppTarget folderTarget = mPredictionModel.getAppTargetFromInfo(folderInfo); - AppTarget itemTarget = mPredictionModel.getAppTargetFromInfo(itemInfo); - if (folderTarget != null && HotseatPredictionModel.isTrackedForPrediction(folderInfo)) { - notifyItemAction(mPredictionModel.wrapAppTargetWithLocation(folderTarget, - AppTargetEvent.ACTION_UNPIN, folderInfo)); - } - if (itemTarget != null && HotseatPredictionModel.isTrackedForPrediction(itemInfo)) { - notifyItemAction(mPredictionModel.wrapAppTargetWithLocation(itemTarget, - AppTargetEvent.ACTION_PIN, itemInfo)); - } - } - @Override public void onDragEnd() { - if (mDragObject == null) { - return; - } - - ItemInfo dragInfo = mDragObject.dragInfo; - if (mDragObject.isMoved()) { - AppTarget appTarget = mPredictionModel.getAppTargetFromInfo(dragInfo); - //always send pin event first to prevent AiAi from predicting an item moved within - // the same page - if (appTarget != null && HotseatPredictionModel.isTrackedForPrediction(dragInfo)) { - notifyItemAction(mPredictionModel.wrapAppTargetWithLocation(appTarget, - AppTargetEvent.ACTION_PIN, dragInfo)); - } - if (appTarget != null && HotseatPredictionModel.isTrackedForPrediction( - mDragObject.originalDragInfo)) { - notifyItemAction(mPredictionModel.wrapAppTargetWithLocation(appTarget, - AppTargetEvent.ACTION_UNPIN, mDragObject.originalDragInfo)); - } - } - mDragObject = null; + mDragInProgress = false; fillGapsWithPrediction(true, this::removeOutlineDrawings); } - @Nullable @Override public SystemShortcut getShortcut(QuickstepLauncher activity, @@ -604,19 +371,7 @@ public class HotseatPredictionController implements DragController.DragListener, @Override public void onIdpChanged(int changeFlags, InvariantDeviceProfile profile) { - if ((changeFlags & CHANGE_FLAG_GRID) != 0) { - this.mHotSeatItemsCount = profile.numHotseatIcons; - createPredictor(); - } - } - - @Override - public void onAppsUpdated() { - fillGapsWithPrediction(); - } - - @Override - public void reapplyItemInfo(ItemInfoWithIcon info) { + this.mHotSeatItemsCount = profile.numHotseatIcons; } @Override @@ -643,17 +398,20 @@ public class HotseatPredictionController implements DragController.DragListener, + ",launchLocation:" + itemInfo.container); } - if (itemInfo.getTargetComponent() == null || itemInfo.user == null) { + + ComponentName targetCN = itemInfo.getTargetComponent(); + if (targetCN == null) { return; } - - final ComponentKey key = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user); - - final List predictedApps = new ArrayList<>(mComponentKeyMappers); - OptionalInt rank = IntStream.range(0, predictedApps.size()) - .filter(index -> key.equals(predictedApps.get(index).getComponentKey())) - .findFirst(); - if (!rank.isPresent()) { + int rank = -1; + for (int i = mPredictedItems.size() - 1; i >= 0; i--) { + ItemInfo info = mPredictedItems.get(i); + if (targetCN.equals(info.getTargetComponent()) && itemInfo.user.equals(info.user)) { + rank = i; + break; + } + } + if (rank < 0) { return; } @@ -666,11 +424,11 @@ public class HotseatPredictionController implements DragController.DragListener, PredictedHotseatContainer.Builder containerBuilder = PredictedHotseatContainer.newBuilder(); containerBuilder.setCardinality(cardinality); if (itemInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) { - containerBuilder.setIndex(rank.getAsInt()); + containerBuilder.setIndex(rank); } mLauncher.getStatsLogManager().logger() .withInstanceId(instanceId) - .withRank(rank.getAsInt()) + .withRank(rank) .withContainerInfo(ContainerInfo.newBuilder() .setPredictedHotseatContainer(containerBuilder) .build()) @@ -691,30 +449,6 @@ public class HotseatPredictionController implements DragController.DragListener, } } - /** - * Fill in predicted_rank field based on app prediction. - * Only applicable when {@link ItemInfo#itemType} is PREDICTED_HOTSEAT - */ - public static void encodeHotseatLayoutIntoPredictionRank( - @NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target) { - QuickstepLauncher launcher = QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity(); - if (launcher == null || launcher.getHotseatPredictionController() == null - || itemInfo.getTargetComponent() == null) { - return; - } - HotseatPredictionController controller = launcher.getHotseatPredictionController(); - - final ComponentKey k = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user); - - final List predictedApps = controller.mComponentKeyMappers; - OptionalInt rank = IntStream.range(0, predictedApps.size()) - .filter((i) -> k.equals(predictedApps.get(i).getComponentKey())) - .findFirst(); - - target.predictedRank = 10000 + (controller.mPredictedSpotsCount * 100) - + (rank.isPresent() ? rank.getAsInt() + 1 : 0); - } - private static boolean isPredictedIcon(View view) { return view instanceof PredictedAppIcon && view.getTag() instanceof WorkspaceItemInfo && ((WorkspaceItemInfo) view.getTag()).container diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java index 5a038d27af..8f31c22d15 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java @@ -15,7 +15,7 @@ */ package com.android.launcher3.hybridhotseat; -import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; @@ -24,13 +24,10 @@ import android.content.ComponentName; import android.content.Context; import android.os.Bundle; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.Workspace; -import com.android.launcher3.model.AllAppsList; -import com.android.launcher3.model.BaseModelUpdateTask; import com.android.launcher3.model.BgDataModel; -import com.android.launcher3.model.PredictionModel; +import com.android.launcher3.model.BgDataModel.FixedContainerItems; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; @@ -38,55 +35,48 @@ import com.android.launcher3.shortcuts.ShortcutKey; import java.util.ArrayList; import java.util.Locale; -import java.util.function.Consumer; /** * Model helper for app predictions in workspace */ -public class HotseatPredictionModel extends PredictionModel { +public class HotseatPredictionModel { private static final String APP_LOCATION_HOTSEAT = "hotseat"; private static final String APP_LOCATION_WORKSPACE = "workspace"; private static final String BUNDLE_KEY_PIN_EVENTS = "pin_events"; private static final String BUNDLE_KEY_CURRENT_ITEMS = "current_items"; - - public HotseatPredictionModel(Context context) { } - /** - * Creates and returns bundle using workspace items and cached items + * Creates and returns bundle using workspace items */ - public void createBundle(Consumer cb) { - LauncherAppState appState = LauncherAppState.getInstance(mContext); - appState.getModel().enqueueModelUpdateTask(new BaseModelUpdateTask() { - @Override - public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) { - Bundle bundle = new Bundle(); - ArrayList events = new ArrayList<>(); - ArrayList workspaceItems = new ArrayList<>(dataModel.workspaceItems); - workspaceItems.addAll(dataModel.appWidgets); - for (ItemInfo item : workspaceItems) { - AppTarget target = getAppTargetFromInfo(item); - if (target != null && !isTrackedForPrediction(item)) continue; - events.add(wrapAppTargetWithLocation(target, AppTargetEvent.ACTION_PIN, item)); - } - ArrayList currentTargets = new ArrayList<>(); - for (ItemInfo itemInfo : dataModel.cachedPredictedItems) { - AppTarget target = getAppTargetFromInfo(itemInfo); - if (target != null) currentTargets.add(target); - } - bundle.putParcelableArrayList(BUNDLE_KEY_PIN_EVENTS, events); - bundle.putParcelableArrayList(BUNDLE_KEY_CURRENT_ITEMS, currentTargets); - MAIN_EXECUTOR.execute(() -> cb.accept(bundle)); + public static Bundle convertDataModelToAppTargetBundle(Context context, BgDataModel dataModel) { + Bundle bundle = new Bundle(); + ArrayList events = new ArrayList<>(); + ArrayList workspaceItems = new ArrayList<>(dataModel.workspaceItems); + workspaceItems.addAll(dataModel.appWidgets); + for (ItemInfo item : workspaceItems) { + AppTarget target = getAppTargetFromInfo(context, item); + if (target != null && !isTrackedForPrediction(item)) continue; + events.add(wrapAppTargetWithLocation(target, AppTargetEvent.ACTION_PIN, item)); + } + ArrayList currentTargets = new ArrayList<>(); + FixedContainerItems hotseatItems = dataModel.extraItems.get(CONTAINER_HOTSEAT_PREDICTION); + if (hotseatItems != null) { + for (ItemInfo itemInfo : hotseatItems.items) { + AppTarget target = getAppTargetFromInfo(context, itemInfo); + if (target != null) currentTargets.add(target); } - }); + } + bundle.putParcelableArrayList(BUNDLE_KEY_PIN_EVENTS, events); + bundle.putParcelableArrayList(BUNDLE_KEY_CURRENT_ITEMS, currentTargets); + return bundle; } /** * Creates and returns for {@link AppTarget} object given an {@link ItemInfo}. Returns null * if item is not supported prediction */ - public AppTarget getAppTargetFromInfo(ItemInfo info) { + public static AppTarget getAppTargetFromInfo(Context context, ItemInfo info) { if (info == null) return null; if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && info instanceof LauncherAppWidgetInfo @@ -107,17 +97,17 @@ public class HotseatPredictionModel extends PredictionModel { shortcutKey.componentName.getPackageName(), shortcutKey.user).build(); } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { return new AppTarget.Builder(new AppTargetId("folder:" + info.id), - mContext.getPackageName(), info.user).build(); + context.getPackageName(), info.user).build(); } return null; } - /** * Creates and returns {@link AppTargetEvent} from an {@link AppTarget}, action, and item * location using {@link ItemInfo} */ - public AppTargetEvent wrapAppTargetWithLocation(AppTarget target, int action, ItemInfo info) { + public static AppTargetEvent wrapAppTargetWithLocation( + AppTarget target, int action, ItemInfo info) { String location = String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]", info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT ? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE, diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java index 9e7c9fba6d..90f762e24c 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java @@ -19,8 +19,10 @@ import static com.android.launcher3.LauncherSettings.Favorites.HYBRID_HOTSEAT_BA import static com.android.launcher3.provider.LauncherDbUtils.tableExists; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; +import android.content.Context; + import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.model.GridBackupTable; import com.android.launcher3.provider.LauncherDbUtils; @@ -29,29 +31,24 @@ import com.android.launcher3.provider.LauncherDbUtils; * A helper class to manage migration revert restoration for hybrid hotseat */ public class HotseatRestoreHelper { - private final Launcher mLauncher; - - HotseatRestoreHelper(Launcher context) { - mLauncher = context; - } /** * Creates a snapshot backup of Favorite table for future restoration use. */ - public void createBackup() { + public static void createBackup(Context context) { MODEL_EXECUTOR.execute(() -> { try (LauncherDbUtils.SQLiteTransaction transaction = (LauncherDbUtils.SQLiteTransaction) LauncherSettings.Settings.call( - mLauncher.getContentResolver(), + context.getContentResolver(), LauncherSettings.Settings.METHOD_NEW_TRANSACTION) .getBinder(LauncherSettings.Settings.EXTRA_VALUE)) { - InvariantDeviceProfile idp = mLauncher.getDeviceProfile().inv; - GridBackupTable backupTable = new GridBackupTable(mLauncher, + InvariantDeviceProfile idp = LauncherAppState.getIDP(context); + GridBackupTable backupTable = new GridBackupTable(context, transaction.getDb(), idp.numHotseatIcons, idp.numColumns, idp.numRows); backupTable.createCustomBackupTable(HYBRID_HOTSEAT_BACKUP_TABLE); transaction.commit(); - LauncherSettings.Settings.call(mLauncher.getContentResolver(), + LauncherSettings.Settings.call(context.getContentResolver(), LauncherSettings.Settings.METHOD_REFRESH_HOTSEAT_RESTORE_TABLE); } }); @@ -60,23 +57,23 @@ public class HotseatRestoreHelper { /** * Finds and restores a previously saved snapshow of Favorites table */ - public void restoreBackup() { + public static void restoreBackup(Context context) { MODEL_EXECUTOR.execute(() -> { try (LauncherDbUtils.SQLiteTransaction transaction = (LauncherDbUtils.SQLiteTransaction) LauncherSettings.Settings.call( - mLauncher.getContentResolver(), + context.getContentResolver(), LauncherSettings.Settings.METHOD_NEW_TRANSACTION) .getBinder(LauncherSettings.Settings.EXTRA_VALUE)) { if (!tableExists(transaction.getDb(), HYBRID_HOTSEAT_BACKUP_TABLE)) { return; } - InvariantDeviceProfile idp = mLauncher.getDeviceProfile().inv; - GridBackupTable backupTable = new GridBackupTable(mLauncher, + InvariantDeviceProfile idp = LauncherAppState.getIDP(context); + GridBackupTable backupTable = new GridBackupTable(context, transaction.getDb(), idp.numHotseatIcons, idp.numColumns, idp.numRows); backupTable.restoreFromCustomBackupTable(HYBRID_HOTSEAT_BACKUP_TABLE, true); transaction.commit(); - mLauncher.getModel().forceReload(); + LauncherAppState.getInstance(context).getModel().forceReload(); } }); } diff --git a/quickstep/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java index 8e4c43f464..364a321f75 100644 --- a/quickstep/src/com/android/launcher3/model/AppEventProducer.java +++ b/quickstep/src/com/android/launcher3/model/AppEventProducer.java @@ -15,8 +15,21 @@ */ package com.android.launcher3.model; +import static android.app.prediction.AppTargetEvent.ACTION_DISMISS; +import static android.app.prediction.AppTargetEvent.ACTION_LAUNCH; +import static android.app.prediction.AppTargetEvent.ACTION_PIN; +import static android.app.prediction.AppTargetEvent.ACTION_UNPIN; + +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_PREDICTION_PINNED; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DRAG_STARTED; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_REMOVE; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_FOLDER_CREATED; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_LEFT; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN; @@ -47,11 +60,12 @@ import com.android.launcher3.logger.LauncherAtom.FolderContainer; import com.android.launcher3.logger.LauncherAtom.HotseatContainer; import com.android.launcher3.logger.LauncherAtom.WorkspaceContainer; import com.android.launcher3.logging.StatsLogManager.EventEnum; +import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.pm.UserCache; import com.android.quickstep.logging.StatsLogCompatManager.StatsLogConsumer; import java.util.Locale; -import java.util.function.Consumer; +import java.util.function.ObjIntConsumer; import java.util.function.Predicate; /** @@ -64,9 +78,11 @@ public class AppEventProducer implements StatsLogConsumer { private final Context mContext; private final Handler mMessageHandler; - private final Consumer mCallback; + private final ObjIntConsumer mCallback; - public AppEventProducer(Context context, Consumer callback) { + private LauncherAtom.ItemInfo mLastDragItem; + + public AppEventProducer(Context context, ObjIntConsumer callback) { mContext = context; mMessageHandler = new Handler(MODEL_EXECUTOR.getLooper(), this::handleMessage); mCallback = callback; @@ -76,7 +92,7 @@ public class AppEventProducer implements StatsLogConsumer { private boolean handleMessage(Message msg) { switch (msg.what) { case MSG_LAUNCH: { - mCallback.accept((AppTargetEvent) msg.obj); + mCallback.accept((AppTargetEvent) msg.obj, msg.arg1); return true; } } @@ -84,13 +100,18 @@ public class AppEventProducer implements StatsLogConsumer { } @AnyThread - private void sendEvent(LauncherAtom.ItemInfo atomInfo, int eventId) { - AppTarget target = toAppTarget(atomInfo); + private void sendEvent(LauncherAtom.ItemInfo atomInfo, int eventId, int targetPredictor) { + sendEvent(toAppTarget(atomInfo), atomInfo, eventId, targetPredictor); + } + + @AnyThread + private void sendEvent(AppTarget target, LauncherAtom.ItemInfo locationInfo, int eventId, + int targetPredictor) { if (target != null) { AppTargetEvent event = new AppTargetEvent.Builder(target, eventId) - .setLaunchLocation(getContainer(atomInfo)) + .setLaunchLocation(getContainer(locationInfo)) .build(); - Message.obtain(mMessageHandler, MSG_LAUNCH, event).sendToTarget(); + mMessageHandler.obtainMessage(MSG_LAUNCH, targetPredictor, 0, event).sendToTarget(); } } @@ -101,9 +122,42 @@ public class AppEventProducer implements StatsLogConsumer { || event == LAUNCHER_TASK_LAUNCH_TAP || event == LAUNCHER_QUICKSWITCH_RIGHT || event == LAUNCHER_QUICKSWITCH_LEFT) { - sendEvent(atomInfo, AppTargetEvent.ACTION_LAUNCH); + sendEvent(atomInfo, ACTION_LAUNCH, CONTAINER_PREDICTION); } else if (event == LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST) { - sendEvent(atomInfo, AppTargetEvent.ACTION_DISMISS); + sendEvent(atomInfo, ACTION_DISMISS, CONTAINER_PREDICTION); + } else if (event == LAUNCHER_ITEM_DRAG_STARTED) { + mLastDragItem = atomInfo; + } else if (event == LAUNCHER_ITEM_DROP_COMPLETED) { + if (mLastDragItem == null) { + return; + } + if (isTrackedForHotseatPrediction(atomInfo)) { + sendEvent(atomInfo, ACTION_PIN, CONTAINER_HOTSEAT_PREDICTION); + } + if (isTrackedForHotseatPrediction(mLastDragItem)) { + sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION); + } + mLastDragItem = null; + } else if (event == LAUNCHER_ITEM_DROP_FOLDER_CREATED) { + if (isTrackedForHotseatPrediction(atomInfo)) { + sendEvent(createTempFolderTarget(), atomInfo, ACTION_PIN, + CONTAINER_HOTSEAT_PREDICTION); + sendEvent(atomInfo, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION); + } + } else if (event == LAUNCHER_FOLDER_CONVERTED_TO_ICON) { + if (isTrackedForHotseatPrediction(atomInfo)) { + sendEvent(createTempFolderTarget(), atomInfo, ACTION_UNPIN, + CONTAINER_HOTSEAT_PREDICTION); + sendEvent(atomInfo, ACTION_PIN, CONTAINER_HOTSEAT_PREDICTION); + } + } else if (event == LAUNCHER_ITEM_DROPPED_ON_REMOVE) { + if (mLastDragItem != null && isTrackedForHotseatPrediction(mLastDragItem)) { + sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION); + } + } else if (event == LAUNCHER_HOTSEAT_PREDICTION_PINNED) { + if (isTrackedForHotseatPrediction(atomInfo)) { + sendEvent(atomInfo, ACTION_PIN, CONTAINER_HOTSEAT_PREDICTION); + } } } @@ -152,10 +206,8 @@ public class AppEventProducer implements StatsLogConsumer { } break; } - case FOLDER_ICON: { - id = "folder:" + SystemClock.uptimeMillis(); - cn = new ComponentName(mContext.getPackageName(), "#folder"); - } + case FOLDER_ICON: + return createTempFolderTarget(); } if (id != null && cn != null) { return new AppTarget.Builder(new AppTargetId(id), cn.getPackageName(), userHandle) @@ -165,6 +217,12 @@ public class AppEventProducer implements StatsLogConsumer { return null; } + private AppTarget createTempFolderTarget() { + return new AppTarget.Builder(new AppTargetId("folder:" + SystemClock.uptimeMillis()), + mContext.getPackageName(), Process.myUserHandle()) + .build(); + } + private String getContainer(LauncherAtom.ItemInfo info) { ContainerInfo ci = info.getContainerInfo(); switch (ci.getContainerCase()) { @@ -212,11 +270,26 @@ public class AppEventProducer implements StatsLogConsumer { } private static String getHotseatContainerString(HotseatContainer hc) { - return String.format(Locale.ENGLISH, "hotseat/%d", hc.getIndex()); + return String.format(Locale.ENGLISH, "hotseat/%1$d/[%1$d,0]/[1,1]", hc.getIndex()); } private static ComponentName parseNullable(String componentNameString) { return TextUtils.isEmpty(componentNameString) ? null : ComponentName.unflattenFromString(componentNameString); } + + /** + * Helper method to determine if {@link ItemInfo} should be tracked and reported to predictors + */ + private static boolean isTrackedForHotseatPrediction(LauncherAtom.ItemInfo info) { + ContainerInfo ci = info.getContainerInfo(); + switch (ci.getContainerCase()) { + case HOTSEAT: + return true; + case WORKSPACE: + return ci.getWorkspace().getPageIndex() == 0; + default: + return false; + } + } } diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java index 166cb6cc4d..be57dece79 100644 --- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java +++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java @@ -16,9 +16,11 @@ package com.android.launcher3.model; import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT; +import static com.android.launcher3.hybridhotseat.HotseatPredictionModel.convertDataModelToAppTargetBundle; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppPredictionManager; @@ -62,6 +64,8 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange private final PredictorState mAllAppsState = new PredictorState(CONTAINER_PREDICTION, "all_apps_predictions"); + private final PredictorState mHotseatState = + new PredictorState(CONTAINER_HOTSEAT_PREDICTION, "hotseat_predictions"); private final InvariantDeviceProfile mIDP; private final AppEventProducer mAppEventProducer; @@ -81,13 +85,23 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange // TODO: Implement caching and preloading super.loadItems(ums, pinnedShortcuts); - WorkspaceItemFactory factory = + WorkspaceItemFactory allAppsFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, mIDP.numAllAppsColumns); mAllAppsState.items.setItems( - mAllAppsState.storage.read(mApp.getContext(), factory, ums.allUsers::get)); + mAllAppsState.storage.read(mApp.getContext(), allAppsFactory, ums.allUsers::get)); mDataModel.extraItems.put(CONTAINER_PREDICTION, mAllAppsState.items); + WorkspaceItemFactory hotseatFactory = + new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, mIDP.numHotseatIcons); + mHotseatState.items.setItems( + mHotseatState.storage.read(mApp.getContext(), hotseatFactory, ums.allUsers::get)); + mDataModel.extraItems.put(CONTAINER_HOTSEAT_PREDICTION, mHotseatState.items); mActive = true; + } + + @Override + public void workspaceLoadComplete() { + super.workspaceLoadComplete(); recreatePredictors(); } @@ -111,6 +125,7 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange private void destroyPredictors() { mAllAppsState.destroyPredictor(); + mHotseatState.destroyPredictor(); } @WorkerThread @@ -125,18 +140,28 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange return; } - int count = mIDP.numAllAppsColumns; - - mAllAppsState.predictor = apm.createAppPredictionSession( + registerPredictor(mAllAppsState, apm.createAppPredictionSession( new AppPredictionContext.Builder(context) .setUiSurface("home") - .setPredictedTargetCount(count) - .build()); - mAllAppsState.predictor.registerPredictionUpdates( - Executors.MODEL_EXECUTOR, t -> handleUpdate(mAllAppsState, t)); - mAllAppsState.predictor.requestPredictionUpdate(); + .setPredictedTargetCount(mIDP.numAllAppsColumns) + .build())); + + // TODO: get bundle + registerPredictor(mHotseatState, apm.createAppPredictionSession( + new AppPredictionContext.Builder(context) + .setUiSurface("hotseat") + .setPredictedTargetCount(mIDP.numHotseatIcons) + .setExtras(convertDataModelToAppTargetBundle(context, mDataModel)) + .build())); + } + private void registerPredictor(PredictorState state, AppPredictor predictor) { + state.predictor = predictor; + state.predictor.registerPredictionUpdates( + Executors.MODEL_EXECUTOR, t -> handleUpdate(state, t)); + state.predictor.requestPredictionUpdate(); + } private void handleUpdate(PredictorState state, List targets) { if (state.setTargets(targets)) { @@ -154,9 +179,10 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange } } - private void onAppTargetEvent(AppTargetEvent event) { - if (mAllAppsState.predictor != null) { - mAllAppsState.predictor.notifyAppTargetEvent(event); + private void onAppTargetEvent(AppTargetEvent event, int client) { + PredictorState state = client == CONTAINER_PREDICTION ? mAllAppsState : mHotseatState; + if (state.predictor != null) { + state.predictor.notifyAppTargetEvent(event); } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index f7bc0b32d4..e808f8cb78 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -33,8 +33,8 @@ import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY; import android.content.Intent; +import android.content.SharedPreferences; import android.content.res.Configuration; -import android.os.Bundle; import android.util.Log; import android.view.View; @@ -48,14 +48,11 @@ import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.appprediction.PredictionRowView; import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.folder.Folder; import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.logging.InstanceId; import com.android.launcher3.logging.StatsLogManager.StatsLogger; import com.android.launcher3.model.BgDataModel.FixedContainerItems; -import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory; import com.android.launcher3.testing.TestProtocol; @@ -70,13 +67,14 @@ import com.android.launcher3.uioverrides.touchcontrollers.QuickSwitchTouchContro import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController; import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController; import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController; -import com.android.launcher3.util.IntArray; +import com.android.launcher3.util.OnboardingPrefs; import com.android.launcher3.util.TouchController; import com.android.launcher3.util.UiThreadHelper; import com.android.launcher3.util.UiThreadHelper.AsyncCommand; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.SystemUiProxy; +import com.android.quickstep.util.QuickstepOnboardingPrefs; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -84,7 +82,6 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.List; import java.util.Objects; import java.util.stream.Stream; @@ -98,14 +95,7 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { SystemUiProxy.INSTANCE.get(context).setShelfHeight(arg1 != 0, arg2); private FixedContainerItems mAllAppsPredictions; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (mHotseatPredictionController != null) { - mHotseatPredictionController.createPredictor(); - } - } + private HotseatPredictionController mHotseatPredictionController; @Override protected void setupViews() { @@ -143,6 +133,18 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { } } + /** + * Returns Prediction controller for hybrid hotseat + */ + public HotseatPredictionController getHotseatPredictionController() { + return mHotseatPredictionController; + } + + @Override + protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) { + return new QuickstepOnboardingPrefs(this, sharedPrefs); + } + @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); @@ -178,22 +180,6 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { super.showAllAppsFromIntent(alreadyOnHome); } - @Override - public void folderCreatedFromItem(Folder folder, WorkspaceItemInfo itemInfo) { - super.folderCreatedFromItem(folder, itemInfo); - if (mHotseatPredictionController != null) { - mHotseatPredictionController.folderCreatedFromWorkspaceItem(itemInfo, folder.getInfo()); - } - } - - @Override - public void folderConvertedToItem(Folder folder, WorkspaceItemInfo itemInfo) { - super.folderConvertedToItem(folder, itemInfo); - if (mHotseatPredictionController != null) { - mHotseatPredictionController.folderConvertedToWorkspaceItem(itemInfo, folder.getInfo()); - } - } - @Override public Stream getSupportedShortcuts() { if (mHotseatPredictionController != null) { @@ -221,20 +207,15 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { } } - @Override - public void bindPredictedItems(List appInfos, IntArray ranks) { - super.bindPredictedItems(appInfos, ranks); - if (mHotseatPredictionController != null) { - mHotseatPredictionController.showCachedItems(appInfos, ranks); - } - } - @Override public void bindExtraContainerItems(FixedContainerItems item) { if (item.containerId == Favorites.CONTAINER_PREDICTION) { mAllAppsPredictions = item; getAppsView().getFloatingHeaderView().findFixedRowByType(PredictionRowView.class) .setPredictedApps(item.items); + } else if (item.containerId == Favorites.CONTAINER_HOTSEAT_PREDICTION + && mHotseatPredictionController != null) { + mHotseatPredictionController.setPredictedItems(item); } } diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java index 7eda627934..b10adb43b5 100644 --- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java +++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java @@ -26,13 +26,13 @@ import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview; import android.content.SharedPreferences; -import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.LauncherState; import com.android.launcher3.Workspace; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.statemanager.StateManager.StateListener; +import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.OnboardingPrefs; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.views.AllAppsEduView; @@ -40,9 +40,9 @@ import com.android.quickstep.views.AllAppsEduView; /** * Extends {@link OnboardingPrefs} for quickstep-specific onboarding data. */ -public class QuickstepOnboardingPrefs extends OnboardingPrefs { +public class QuickstepOnboardingPrefs extends OnboardingPrefs { - public QuickstepOnboardingPrefs(BaseQuickstepLauncher launcher, SharedPreferences sharedPrefs) { + public QuickstepOnboardingPrefs(QuickstepLauncher launcher, SharedPreferences sharedPrefs) { super(launcher, sharedPrefs); StateManager stateManager = launcher.getStateManager(); diff --git a/res/values/config.xml b/res/values/config.xml index dc8bdffca3..fc0a5e10dc 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -69,7 +69,6 @@ - diff --git a/src/com/android/launcher3/DropTarget.java b/src/com/android/launcher3/DropTarget.java index b27abc4369..fd4c30c6f2 100644 --- a/src/com/android/launcher3/DropTarget.java +++ b/src/com/android/launcher3/DropTarget.java @@ -113,18 +113,6 @@ public interface DropTarget { return res; } - - - /** - * This is used to determine if an object is dropped at a different location than it was - * dragged from - */ - public boolean isMoved() { - return dragInfo.cellX != originalDragInfo.cellX - || dragInfo.cellY != originalDragInfo.cellY - || dragInfo.screenId != originalDragInfo.screenId - || dragInfo.container != originalDragInfo.container; - } } /** diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 53b65e812f..cbb577af74 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -108,7 +108,6 @@ import com.android.launcher3.dot.DotInfo; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragView; -import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderGridOrganizer; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.icons.IconCache; @@ -1742,16 +1741,6 @@ public class Launcher extends StatefulActivity implements Launche return newFolder; } - /** - * Called when a workspace item is converted into a folder - */ - public void folderCreatedFromItem(Folder folder, WorkspaceItemInfo itemInfo){} - - /** - * Called when a folder is converted into a workspace item - */ - public void folderConvertedToItem(Folder folder, WorkspaceItemInfo itemInfo) {} - /** * Unbinds the view for the specified item, and removes the item and all its children. * @@ -2189,9 +2178,6 @@ public class Launcher extends StatefulActivity implements Launche workspace.requestLayout(); } - @Override - public void bindPredictedItems(List appInfos, IntArray ranks) { } - /** * Add the views for a widget to the workspace. */ diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 782a8699cc..b278e81655 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -33,7 +33,6 @@ import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.IconProvider; import com.android.launcher3.icons.LauncherIcons; -import com.android.launcher3.model.PredictionModel; import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.pm.InstallSessionHelper; import com.android.launcher3.pm.InstallSessionTracker; @@ -58,7 +57,6 @@ public class LauncherAppState { private final IconCache mIconCache; private final WidgetPreviewLoader mWidgetCache; private final InvariantDeviceProfile mInvariantDeviceProfile; - private final PredictionModel mPredictionModel; private SecureSettingsObserver mNotificationDotsObserver; private InstallSessionTracker mInstallSessionTracker; @@ -125,7 +123,6 @@ public class LauncherAppState { mIconCache = new IconCache(mContext, mInvariantDeviceProfile, iconCacheFileName); mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache); mModel = new LauncherModel(context, this, mIconCache, AppFilter.newInstance(mContext)); - mPredictionModel = PredictionModel.newInstance(mContext); } protected void onNotificationSettingsChanged(boolean areNotificationDotsEnabled) { @@ -182,10 +179,6 @@ public class LauncherAppState { return mModel; } - public PredictionModel getPredictionModel() { - return mPredictionModel; - } - public WidgetPreviewLoader getWidgetCache() { return mWidgetCache; } diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index f58e0b496a..6aa4c430b1 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -217,6 +217,13 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi } } + /** + * Called when the workspace items have drastically changed + */ + public void onWorkspaceUiChanged() { + MODEL_EXECUTOR.execute(mModelDelegate::workspaceLoadComplete); + } + /** * Called when the model is destroyed */ diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 3be9ac7e07..252e64e534 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1702,7 +1702,6 @@ public class Workspace extends PagedView fi.addItem(destInfo); fi.addItem(sourceInfo); } - mLauncher.folderCreatedFromItem(fi.getFolder(), destInfo); return true; } return false; @@ -1719,7 +1718,7 @@ public class Workspace extends PagedView if (dropOverView instanceof FolderIcon) { FolderIcon fi = (FolderIcon) dropOverView; if (fi.acceptDrop(d.dragInfo)) { - mStatsLogManager.logger().withItemInfo(fi.mInfo).withInstanceId(d.logInstanceId) + mStatsLogManager.logger().withItemInfo(d.dragInfo).withInstanceId(d.logInstanceId) .log(LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED); fi.onDrop(d, false /* itemReturnedOnFailedDrop */); diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index b91d1c3260..61543c4ce5 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -24,6 +24,7 @@ import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; import static com.android.launcher3.config.FeatureFlags.ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS; import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_LABEL_UPDATED; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED; @@ -1183,7 +1184,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo newIcon.requestFocus(); } if (finalItem != null) { - mLauncher.folderConvertedToItem(mFolderIcon.getFolder(), finalItem); + mStatsLogManager.logger().withItemInfo(finalItem) + .log(LAUNCHER_FOLDER_CONVERTED_TO_ICON); } } } diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java index cca9836835..0f1432a9b6 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -19,6 +19,7 @@ import static android.view.View.MeasureSpec.EXACTLY; import static android.view.View.MeasureSpec.makeMeasureSpec; import static android.view.View.VISIBLE; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; import static com.android.launcher3.config.FeatureFlags.ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER; import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems; import static com.android.launcher3.model.ModelUtils.getMissingHotseatRanks; @@ -72,12 +73,12 @@ import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.model.AllAppsList; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.BgDataModel.Callbacks; +import com.android.launcher3.model.BgDataModel.FixedContainerItems; import com.android.launcher3.model.LoaderResults; import com.android.launcher3.model.LoaderTask; import com.android.launcher3.model.ModelDelegate; import com.android.launcher3.model.WidgetItem; import com.android.launcher3.model.WidgetsModel; -import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; @@ -95,6 +96,7 @@ import com.android.launcher3.widget.custom.CustomWidgetManager; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -467,12 +469,14 @@ public class LauncherPreviewRenderer extends ContextThemeWrapper } IntArray ranks = getMissingHotseatRanks(currentWorkspaceItems, mIdp.numHotseatIcons); - int count = Math.min(ranks.size(), workspaceResult.mCachedPredictedItems.size()); + List predictions = workspaceResult.mHotseatPredictions == null + ? Collections.emptyList() : workspaceResult.mHotseatPredictions.items; + int count = Math.min(ranks.size(), predictions.size()); for (int i = 0; i < count; i++) { - AppInfo appInfo = workspaceResult.mCachedPredictedItems.get(i); int rank = ranks.get(i); - WorkspaceItemInfo itemInfo = new WorkspaceItemInfo(appInfo); - itemInfo.container = Favorites.CONTAINER_HOTSEAT_PREDICTION; + WorkspaceItemInfo itemInfo = + new WorkspaceItemInfo((WorkspaceItemInfo) predictions.get(i)); + itemInfo.container = CONTAINER_HOTSEAT_PREDICTION; itemInfo.rank = rank; itemInfo.cellX = mHotseat.getCellXFromOrder(rank); itemInfo.cellY = mHotseat.getCellYFromOrder(rank); @@ -569,8 +573,7 @@ public class LauncherPreviewRenderer extends ContextThemeWrapper return null; } - return new WorkspaceResult(mBgDataModel.workspaceItems, mBgDataModel.appWidgets, - mBgDataModel.cachedPredictedItems, mBgDataModel.widgetsModel, null); + return new WorkspaceResult(mBgDataModel, mBgDataModel.widgetsModel, null); } } @@ -594,11 +597,10 @@ public class LauncherPreviewRenderer extends ContextThemeWrapper } @Override - public WorkspaceResult call() throws Exception { + public WorkspaceResult call() { List allShortcuts = new ArrayList<>(); loadWorkspace(allShortcuts, LauncherSettings.Favorites.PREVIEW_CONTENT_URI); - return new WorkspaceResult(mBgDataModel.workspaceItems, mBgDataModel.appWidgets, - mBgDataModel.cachedPredictedItems, null, mWidgetProvidersMap); + return new WorkspaceResult(mBgDataModel, null, mWidgetProvidersMap); } } @@ -618,17 +620,16 @@ public class LauncherPreviewRenderer extends ContextThemeWrapper private static class WorkspaceResult { private final ArrayList mWorkspaceItems; private final ArrayList mAppWidgets; - private final ArrayList mCachedPredictedItems; + private final FixedContainerItems mHotseatPredictions; private final WidgetsModel mWidgetsModel; private final Map mWidgetProvidersMap; - private WorkspaceResult(ArrayList workspaceItems, - ArrayList appWidgets, - ArrayList cachedPredictedItems, WidgetsModel widgetsModel, + private WorkspaceResult(BgDataModel dataModel, + WidgetsModel widgetsModel, Map widgetProviderInfoMap) { - mWorkspaceItems = workspaceItems; - mAppWidgets = appWidgets; - mCachedPredictedItems = cachedPredictedItems; + mWorkspaceItems = dataModel.workspaceItems; + mAppWidgets = dataModel.appWidgets; + mHotseatPredictions = dataModel.extraItems.get(CONTAINER_HOTSEAT_PREDICTION); mWidgetsModel = widgetsModel; mWidgetProvidersMap = widgetProviderInfoMap; } diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index 22823391dd..ec1c3ef779 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -316,7 +316,13 @@ public class StatsLogManager implements ResourceBasedOverride { LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON(625), @UiEvent(doc = "User tapped on image content in Overview Select mode.") - LAUNCHER_SELECT_MODE_IMAGE(627); + LAUNCHER_SELECT_MODE_IMAGE(627), + + @UiEvent(doc = "A folder was replaced by a single item") + LAUNCHER_FOLDER_CONVERTED_TO_ICON(628), + + @UiEvent(doc = "A hotseat prediction item was pinned") + LAUNCHER_HOTSEAT_PREDICTION_PINNED(629); // ADD MORE diff --git a/src/com/android/launcher3/model/BaseLoaderResults.java b/src/com/android/launcher3/model/BaseLoaderResults.java index 586333fd2e..5c85babb76 100644 --- a/src/com/android/launcher3/model/BaseLoaderResults.java +++ b/src/com/android/launcher3/model/BaseLoaderResults.java @@ -17,7 +17,6 @@ package com.android.launcher3.model; import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems; -import static com.android.launcher3.model.ModelUtils.getMissingHotseatRanks; import static com.android.launcher3.model.ModelUtils.sortWorkspaceItemsSpatially; import android.util.Log; @@ -206,9 +205,6 @@ public abstract class BaseLoaderResults { mExtraItems.forEach(item -> executeCallbacksTask(c -> c.bindExtraContainerItems(item), mainExecutor)); - // Locate available spots for prediction using currentWorkspaceItems - IntArray gaps = getMissingHotseatRanks(currentWorkspaceItems, idp.numHotseatIcons); - bindPredictedItems(gaps, mainExecutor); // In case of validFirstPage, only bind the first screen, and defer binding the // remaining screens after first onDraw (and an optional the fade animation whichever // happens later). @@ -261,11 +257,6 @@ public abstract class BaseLoaderResults { } } - private void bindPredictedItems(IntArray ranks, final Executor executor) { - ArrayList items = new ArrayList<>(mBgDataModel.cachedPredictedItems); - executeCallbacksTask(c -> c.bindPredictedItems(items, ranks), executor); - } - protected void executeCallbacksTask(CallbackTask task, Executor executor) { executor.execute(() -> { if (mMyBindingId != mBgDataModel.lastBindId) { diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java index 140342f98c..1fc897af7c 100644 --- a/src/com/android/launcher3/model/BgDataModel.java +++ b/src/com/android/launcher3/model/BgDataModel.java @@ -103,11 +103,6 @@ public class BgDataModel { */ public final IntSparseArrayMap extraItems = new IntSparseArrayMap<>(); - /** - * List of all cached predicted items visible on home screen - */ - public final ArrayList cachedPredictedItems = new ArrayList<>(); - /** * Maps all launcher activities to counts of their shortcuts. */ @@ -472,10 +467,5 @@ public class BgDataModel { default void bindExtraContainerItems(FixedContainerItems item) { } void bindAllApplications(AppInfo[] apps, int flags); - - /** - * Binds predicted appInfos at at available prediction slots. - */ - void bindPredictedItems(List appInfos, IntArray ranks); } } diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 1dd8c112c6..983ec0c176 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -48,8 +48,6 @@ import android.util.Log; import android.util.LongSparseArray; import android.util.TimingLogger; -import androidx.annotation.WorkerThread; - import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherSettings; @@ -190,13 +188,13 @@ public class LoaderTask implements Runnable { try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { List allShortcuts = new ArrayList<>(); loadWorkspace(allShortcuts); - loadCachedPredictions(); logger.addSplit("loadWorkspace"); verifyNotStopped(); mResults.bindWorkspace(); logger.addSplit("bindWorkspace"); + mModelDelegate.workspaceLoadComplete(); // Notify the installer packages of packages with active installs on the first screen. sendFirstScreenActiveInstallsBroadcast(); logger.addSplit("sendFirstScreenActiveInstallsBroadcast"); @@ -839,24 +837,6 @@ public class LoaderTask implements Runnable { } } - @WorkerThread - private void loadCachedPredictions() { - synchronized (mBgDataModel) { - List componentKeys = - mApp.getPredictionModel().getPredictionComponentKeys(); - List l; - mBgDataModel.cachedPredictedItems.clear(); - for (ComponentKey key : componentKeys) { - l = mLauncherApps.getActivityList(key.componentName.getPackageName(), key.user); - if (l.size() == 0) continue; - AppInfo info = new AppInfo(l.get(0), key.user, - mUserManagerState.isUserQuiet(key.user)); - mBgDataModel.cachedPredictedItems.add(info); - mIconCache.getTitleAndIcon(info, false); - } - } - } - private void sanitizeData() { Context context = mApp.getContext(); if (mItemsDeleted) { @@ -900,14 +880,6 @@ public class LoaderTask implements Runnable { PackageInstallInfo.fromInstallingState(info)); } } - for (AppInfo item : mBgDataModel.cachedPredictedItems) { - List l = mLauncherApps.getActivityList( - item.componentName.getPackageName(), item.user); - for (LauncherActivityInfo info : l) { - boolean quietMode = mUserManagerState.isUserQuiet(item.user); - mBgAllAppsList.add(new AppInfo(info, item.user, quietMode), info); - } - } mBgAllAppsList.setFlags(FLAG_QUIET_MODE_ENABLED, mUserManagerState.isAnyProfileQuietModeEnabled()); diff --git a/src/com/android/launcher3/model/ModelDelegate.java b/src/com/android/launcher3/model/ModelDelegate.java index 53e8a86078..3ed880906d 100644 --- a/src/com/android/launcher3/model/ModelDelegate.java +++ b/src/com/android/launcher3/model/ModelDelegate.java @@ -71,6 +71,12 @@ public class ModelDelegate implements ResourceBasedOverride { @WorkerThread public void loadItems(UserManagerState ums, Map pinnedShortcuts) { } + /** + * Called during loader after workspace loading is complete + */ + @WorkerThread + public void workspaceLoadComplete() { } + /** * Called when the delegate is no loner needed */ diff --git a/src/com/android/launcher3/model/PredictionModel.java b/src/com/android/launcher3/model/PredictionModel.java deleted file mode 100644 index cb3903d4ed..0000000000 --- a/src/com/android/launcher3/model/PredictionModel.java +++ /dev/null @@ -1,136 +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.model; - -import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; - -import android.content.ComponentName; -import android.content.Context; -import android.content.SharedPreferences; -import android.os.UserHandle; - -import androidx.annotation.AnyThread; -import androidx.annotation.WorkerThread; - -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.R; -import com.android.launcher3.Utilities; -import com.android.launcher3.pm.UserCache; -import com.android.launcher3.util.ComponentKey; -import com.android.launcher3.util.Preconditions; -import com.android.launcher3.util.ResourceBasedOverride; - -import java.util.ArrayList; -import java.util.List; - -/** - * Model Helper for app predictions - */ -public class PredictionModel implements ResourceBasedOverride { - - private static final String CACHED_ITEMS_KEY = "predicted_item_keys"; - private static final int MAX_CACHE_ITEMS = 5; - - protected Context mContext; - private SharedPreferences mDevicePrefs; - private UserCache mUserCache; - - - /** - * Retrieve instance of this object that can be overridden in runtime based on the build - * variant of the application. - */ - public static PredictionModel newInstance(Context context) { - PredictionModel model = Overrides.getObject(PredictionModel.class, context, - R.string.prediction_model_class); - model.init(context); - return model; - } - - protected void init(Context context) { - mContext = context; - mDevicePrefs = Utilities.getDevicePrefs(mContext); - mUserCache = UserCache.INSTANCE.get(mContext); - - } - - /** - * Formats and stores a list of component key in device preferences. - */ - @AnyThread - public void cachePredictionComponentKeys(List componentKeys) { - MODEL_EXECUTOR.execute(() -> { - LauncherAppState appState = LauncherAppState.getInstance(mContext); - StringBuilder builder = new StringBuilder(); - int count = Math.min(componentKeys.size(), MAX_CACHE_ITEMS); - for (int i = 0; i < count; i++) { - builder.append(serializeComponentKeyToString(componentKeys.get(i))); - builder.append("\n"); - } - if (componentKeys.isEmpty() /* should invalidate loader items */) { - appState.getModel().enqueueModelUpdateTask(new BaseModelUpdateTask() { - @Override - public void execute(LauncherAppState app, BgDataModel model, AllAppsList apps) { - model.cachedPredictedItems.clear(); - } - }); - } - mDevicePrefs.edit().putString(CACHED_ITEMS_KEY, builder.toString()).apply(); - }); - } - - /** - * parses and returns ComponentKeys saved by - * {@link PredictionModel#cachePredictionComponentKeys(List)} - */ - @WorkerThread - public List getPredictionComponentKeys() { - Preconditions.assertWorkerThread(); - ArrayList items = new ArrayList<>(); - String cachedBlob = mDevicePrefs.getString(CACHED_ITEMS_KEY, ""); - for (String line : cachedBlob.split("\n")) { - ComponentKey key = getComponentKeyFromSerializedString(line); - if (key != null) { - items.add(key); - } - - } - return items; - } - - private String serializeComponentKeyToString(ComponentKey componentKey) { - long userSerialNumber = mUserCache.getSerialNumberForUser(componentKey.user); - return componentKey.componentName.flattenToString() + "#" + userSerialNumber; - } - - private ComponentKey getComponentKeyFromSerializedString(String str) { - int sep = str.indexOf('#'); - if (sep < 0 || (sep + 1) >= str.length()) { - return null; - } - ComponentName componentName = ComponentName.unflattenFromString(str.substring(0, sep)); - if (componentName == null) { - return null; - } - try { - long serialNumber = Long.parseLong(str.substring(sep + 1)); - UserHandle userHandle = mUserCache.getUserForSerialNumber(serialNumber); - return userHandle != null ? new ComponentKey(componentName, userHandle) : null; - } catch (NumberFormatException ex) { - return null; - } - } -} diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java index 31c3014874..2b04365ddc 100644 --- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java +++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java @@ -196,9 +196,6 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity @Override public void bindItems(List shortcuts, boolean forceAnimateIcons) { } - @Override - public void bindPredictedItems(List appInfos, IntArray ranks) { } - @Override public void bindScreens(IntArray orderedScreenIds) { } diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java index 6e5e7d9355..1b33197879 100644 --- a/src/com/android/launcher3/util/OnboardingPrefs.java +++ b/src/com/android/launcher3/util/OnboardingPrefs.java @@ -44,7 +44,8 @@ public class OnboardingPrefs { */ @StringDef(value = { HOME_BOUNCE_SEEN, - SHELF_BOUNCE_SEEN + SHELF_BOUNCE_SEEN, + HOTSEAT_LONGPRESS_TIP_SEEN }) @Retention(RetentionPolicy.SOURCE) public @interface EventBoolKey {} From af8516254ed50e4c1c3d1db198344b4439e1aa5e Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Fri, 21 Aug 2020 23:44:20 -0700 Subject: [PATCH 02/12] Get rid of grid options pref Missed this one last time Test: N/A Change-Id: I7ecfa72f2f358342ea9f8296cdc5d0187498426b --- res/xml/launcher_preferences.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/res/xml/launcher_preferences.xml b/res/xml/launcher_preferences.xml index 3455cb8661..7e7220813a 100644 --- a/res/xml/launcher_preferences.xml +++ b/res/xml/launcher_preferences.xml @@ -44,12 +44,6 @@ android:defaultValue="@bool/allow_rotation" android:persistent="true" /> - - Date: Mon, 24 Aug 2020 16:24:34 -0700 Subject: [PATCH 03/12] Fix a couple issues with overview to home transition - In fake portrait, fade out instead of translating offscreen, as the orientation doesn't map to where RecentsView actually lives - From OverviewModalTaskState, start from > 1 scale, and use OverviewToHomeAnim (to ensure RecentsView doesn't fade out etc) - To keep parameter list sane, added RecentsParams to AnimatorControllerWithResistance which has the new startScale (set to current scale for modal state) and renames the old RecentsParams to RecentsResistanceParams. Sorry if that's confusing. Bug: 144170434 Change-Id: I437f0d18cad4c94feea25954aed3390acedcaed5 --- .../NavBarToHomeTouchController.java | 3 +- .../AnimatorControllerWithResistance.java | 133 +++++++++++++----- .../quickstep/util/OverviewToHomeAnim.java | 9 +- 3 files changed, 105 insertions(+), 40 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java index da3c4858a8..e3d949851d 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java @@ -19,7 +19,6 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_ALL; import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_APPS_EDU; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; -import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS; import static com.android.launcher3.anim.Interpolators.DEACCEL_3; import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_EDU; @@ -221,7 +220,7 @@ public class NavBarToHomeTouchController implements TouchController, recentsView.switchToScreenshot(null, () -> recentsView.finishRecentsAnimation(true /* toRecents */, null)); } - if (mStartState == OVERVIEW) { + if (mStartState.overviewUi) { new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(mEndState)) .animateWithVelocity(velocity); } else { diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java index a19a67c8fc..deb70e0f8b 100644 --- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java +++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java @@ -31,11 +31,12 @@ import android.util.FloatProperty; import androidx.annotation.Nullable; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Launcher; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.touch.PagedOrientationHandler; import com.android.quickstep.LauncherActivityInterface; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.views.RecentsView; @@ -54,11 +55,12 @@ public class AnimatorControllerWithResistance { */ public static final float TWO_BUTTON_EXTRA_DRAG_FACTOR = 0.25f; - private enum RecentsParams { + private enum RecentsResistanceParams { FROM_APP(0.75f, 0.5f, 1f), FROM_OVERVIEW(1f, 0.75f, 0.5f); - RecentsParams(float scaleStartResist, float scaleMaxResist, float translationFactor) { + RecentsResistanceParams(float scaleStartResist, float scaleMaxResist, + float translationFactor) { this.scaleStartResist = scaleStartResist; this.scaleMaxResist = scaleMaxResist; this.translationFactor = translationFactor; @@ -139,9 +141,9 @@ public class AnimatorControllerWithResistance { FloatProperty scaleProperty, TRANSLATION translationTarget, FloatProperty translationProperty) { - PendingAnimation resistAnim = createRecentsResistanceAnim(null, context, - recentsOrientedState, dp, scaleTarget, scaleProperty, translationTarget, - translationProperty, RecentsParams.FROM_APP); + RecentsParams params = new RecentsParams(context, recentsOrientedState, dp, scaleTarget, + scaleProperty, translationTarget, translationProperty); + PendingAnimation resistAnim = createRecentsResistanceAnim(params); AnimatorPlaybackController resistanceController = resistAnim.createPlaybackController(); return new AnimatorControllerWithResistance(normalController, resistanceController); @@ -152,31 +154,30 @@ public class AnimatorControllerWithResistance { * when starting from recents, i.e. {@link #createRecentsResistanceFromOverviewAnim}. */ public static PendingAnimation createRecentsResistanceAnim( - @Nullable PendingAnimation resistAnim, Context context, - RecentsOrientedState recentsOrientedState, DeviceProfile dp, SCALE scaleTarget, - FloatProperty scaleProperty, TRANSLATION translationTarget, - FloatProperty translationProperty, RecentsParams params) { + RecentsParams params) { Rect startRect = new Rect(); - LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, startRect, - recentsOrientedState.getOrientationHandler()); + PagedOrientationHandler orientationHandler = params.recentsOrientedState + .getOrientationHandler(); + LauncherActivityInterface.INSTANCE.calculateTaskSize(params.context, params.dp, startRect, + orientationHandler); long distanceToCover = startRect.bottom; - boolean isTwoButtonMode = SysUINavigationMode.getMode(context) == TWO_BUTTONS; + boolean isTwoButtonMode = SysUINavigationMode.getMode(params.context) == TWO_BUTTONS; if (isTwoButtonMode) { // We can only drag a small distance past overview, not to the top of the screen. distanceToCover = (long) - ((dp.heightPx - startRect.bottom) * TWO_BUTTON_EXTRA_DRAG_FACTOR); - } - if (resistAnim == null) { - resistAnim = new PendingAnimation(distanceToCover * 2); + ((params.dp.heightPx - startRect.bottom) * TWO_BUTTON_EXTRA_DRAG_FACTOR); } + PendingAnimation resistAnim = params.resistAnim != null + ? params.resistAnim + : new PendingAnimation(distanceToCover * 2); PointF pivot = new PointF(); - float fullscreenScale = recentsOrientedState.getFullScreenScaleAndPivot( - startRect, dp, pivot); - float startScale = 1; - float prevScaleRate = (fullscreenScale - startScale) / (dp.heightPx - startRect.bottom); + float fullscreenScale = params.recentsOrientedState.getFullScreenScaleAndPivot( + startRect, params.dp, pivot); + float prevScaleRate = (fullscreenScale - params.startScale) + / (params.dp.heightPx - startRect.bottom); // This is what the scale would be at the end of the drag if we didn't apply resistance. - float endScale = startScale - prevScaleRate * distanceToCover; + float endScale = params.startScale - prevScaleRate * distanceToCover; final TimeInterpolator scaleInterpolator; if (isTwoButtonMode) { // We are bounded by the distance of the drag, so we don't need to apply resistance. @@ -184,9 +185,10 @@ public class AnimatorControllerWithResistance { } else { // Create an interpolator that resists the scale so the scale doesn't get smaller than // RECENTS_SCALE_MAX_RESIST. - float startResist = Utilities.getProgress(params.scaleStartResist , startScale, - endScale); - float maxResist = Utilities.getProgress(params.scaleMaxResist, startScale, endScale); + float startResist = Utilities.getProgress(params.resistanceParams.scaleStartResist, + params.startScale, endScale); + float maxResist = Utilities.getProgress(params.resistanceParams.scaleMaxResist, + params.startScale, endScale); scaleInterpolator = t -> { if (t < startResist) { return t; @@ -196,20 +198,22 @@ public class AnimatorControllerWithResistance { return startResist + resistProgress * (maxResist - startResist); }; } - resistAnim.addFloat(scaleTarget, scaleProperty, startScale, endScale, + resistAnim.addFloat(params.scaleTarget, params.scaleProperty, params.startScale, endScale, scaleInterpolator); if (!isTwoButtonMode) { // Compute where the task view would be based on the end scale, if we didn't translate. RectF endRectF = new RectF(startRect); Matrix temp = new Matrix(); - temp.setScale(params.scaleMaxResist, params.scaleMaxResist, pivot.x, pivot.y); + temp.setScale(params.resistanceParams.scaleMaxResist, + params.resistanceParams.scaleMaxResist, pivot.x, pivot.y); temp.mapRect(endRectF); // Translate such that the task view touches the top of the screen when drag does. - float endTranslation = endRectF.top * recentsOrientedState.getOrientationHandler() - .getSecondaryTranslationDirectionFactor() * params.translationFactor; - resistAnim.addFloat(translationTarget, translationProperty, 0, endTranslation, - RECENTS_TRANSLATE_RESIST_INTERPOLATOR); + float endTranslation = endRectF.top + * orientationHandler.getSecondaryTranslationDirectionFactor() + * params.resistanceParams.translationFactor; + resistAnim.addFloat(params.translationTarget, params.translationProperty, + params.startTranslation, endTranslation, RECENTS_TRANSLATE_RESIST_INTERPOLATOR); } return resistAnim; @@ -220,11 +224,66 @@ public class AnimatorControllerWithResistance { * a RecentsView interaction that started from the overview state. */ public static PendingAnimation createRecentsResistanceFromOverviewAnim( - BaseDraggingActivity activity, @Nullable PendingAnimation resistanceAnim) { - RecentsView recentsView = activity.getOverviewPanel(); - return createRecentsResistanceAnim(resistanceAnim, activity, - recentsView.getPagedViewOrientedState(), activity.getDeviceProfile(), - recentsView, RECENTS_SCALE_PROPERTY, recentsView, TASK_SECONDARY_TRANSLATION, - RecentsParams.FROM_OVERVIEW); + Launcher launcher, @Nullable PendingAnimation resistanceAnim) { + RecentsView recentsView = launcher.getOverviewPanel(); + RecentsParams params = new RecentsParams(launcher, recentsView.getPagedViewOrientedState(), + launcher.getDeviceProfile(), recentsView, RECENTS_SCALE_PROPERTY, recentsView, + TASK_SECONDARY_TRANSLATION) + .setResistAnim(resistanceAnim) + .setResistanceParams(RecentsResistanceParams.FROM_OVERVIEW) + .setStartScale(recentsView.getScaleX()); + return createRecentsResistanceAnim(params); + } + + /** + * Params to compute resistance when scaling/translating recents. + */ + private static class RecentsParams { + // These are all required and can't have default values, hence are final. + public final Context context; + public final RecentsOrientedState recentsOrientedState; + public final DeviceProfile dp; + public final SCALE scaleTarget; + public final FloatProperty scaleProperty; + public final TRANSLATION translationTarget; + public final FloatProperty translationProperty; + + // These are not required, or can have a default value that is generally correct. + @Nullable public PendingAnimation resistAnim = null; + public RecentsResistanceParams resistanceParams = RecentsResistanceParams.FROM_APP; + public float startScale = 1f; + public float startTranslation = 0f; + + private RecentsParams(Context context, RecentsOrientedState recentsOrientedState, + DeviceProfile dp, SCALE scaleTarget, FloatProperty scaleProperty, + TRANSLATION translationTarget, FloatProperty translationProperty) { + this.context = context; + this.recentsOrientedState = recentsOrientedState; + this.dp = dp; + this.scaleTarget = scaleTarget; + this.scaleProperty = scaleProperty; + this.translationTarget = translationTarget; + this.translationProperty = translationProperty; + } + + private RecentsParams setResistAnim(PendingAnimation resistAnim) { + this.resistAnim = resistAnim; + return this; + } + + private RecentsParams setResistanceParams(RecentsResistanceParams resistanceParams) { + this.resistanceParams = resistanceParams; + return this; + } + + private RecentsParams setStartScale(float startScale) { + this.startScale = startScale; + return this; + } + + private RecentsParams setStartTranslation(float startTranslation) { + this.startTranslation = startTranslation; + return this; + } } } diff --git a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java index 6278e147c0..4a298d3bad 100644 --- a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java +++ b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java @@ -22,6 +22,7 @@ import static com.android.launcher3.anim.Interpolators.FINAL_FRAME; import static com.android.launcher3.anim.Interpolators.INSTANT; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y; @@ -106,10 +107,16 @@ public class OverviewToHomeAnim { // StaggeredWorkspaceAnim doesn't animate overview, so we handle it here. ? PLAY_ATOMIC_OVERVIEW_PEEK : ANIM_ALL_COMPONENTS; - config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, DEACCEL); + boolean isLayoutNaturalToLauncher = recentsView.getPagedOrientationHandler() + .isLayoutNaturalToLauncher(); + config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, isLayoutNaturalToLauncher + ? DEACCEL : FINAL_FRAME); config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, FINAL_FRAME); config.setInterpolator(ANIM_OVERVIEW_SCALE, FINAL_FRAME); config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, INSTANT); + if (!isLayoutNaturalToLauncher) { + config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL); + } AnimatorSet stateAnim = stateManager.createAtomicAnimation( startState, NORMAL, config); stateAnim.addListener(new AnimationSuccessListener() { From 5c460a466341bb8bf0af2a95ec96e069cd477275 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 24 Aug 2020 16:12:46 -0700 Subject: [PATCH 04/12] Fix a couple issues with overview to home transition - In fake portrait, fade out instead of translating offscreen, as the orientation doesn't map to where RecentsView actually lives - From OverviewModalTaskState, start from > 1 scale, and use OverviewToHomeAnim (to ensure RecentsView doesn't fade out etc) - To keep parameter list sane, added RecentsParams to AnimatorControllerWithResistance which has the new startScale (set to current scale for modal state) and renames the old RecentsParams to RecentsResistanceParams. Sorry if that's confusing. Bug: 144170434 Change-Id: Id36ebde440b398159cef50d95822627fca761527 Merged-In: I437f0d18cad4c94feea25954aed3390acedcaed5 --- .../NavBarToHomeTouchController.java | 3 +- .../quickstep/util/OverviewToHomeAnim.java | 9 +- .../AnimatorControllerWithResistance.java | 133 +++++++++++++----- 3 files changed, 105 insertions(+), 40 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java index 61f6702dcc..95e07e8da5 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java @@ -19,7 +19,6 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_ALL; import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_APPS_EDU; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; -import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS; import static com.android.launcher3.anim.Interpolators.DEACCEL_3; import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_EDU; @@ -222,7 +221,7 @@ public class NavBarToHomeTouchController implements TouchController, recentsView.switchToScreenshot(null, () -> recentsView.finishRecentsAnimation(true /* toRecents */, null)); } - if (mStartState == OVERVIEW) { + if (mStartState.overviewUi) { new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(mEndState)) .animateWithVelocity(velocity); } else { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/OverviewToHomeAnim.java index 6278e147c0..4a298d3bad 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/OverviewToHomeAnim.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/OverviewToHomeAnim.java @@ -22,6 +22,7 @@ import static com.android.launcher3.anim.Interpolators.FINAL_FRAME; import static com.android.launcher3.anim.Interpolators.INSTANT; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y; @@ -106,10 +107,16 @@ public class OverviewToHomeAnim { // StaggeredWorkspaceAnim doesn't animate overview, so we handle it here. ? PLAY_ATOMIC_OVERVIEW_PEEK : ANIM_ALL_COMPONENTS; - config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, DEACCEL); + boolean isLayoutNaturalToLauncher = recentsView.getPagedOrientationHandler() + .isLayoutNaturalToLauncher(); + config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, isLayoutNaturalToLauncher + ? DEACCEL : FINAL_FRAME); config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, FINAL_FRAME); config.setInterpolator(ANIM_OVERVIEW_SCALE, FINAL_FRAME); config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, INSTANT); + if (!isLayoutNaturalToLauncher) { + config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL); + } AnimatorSet stateAnim = stateManager.createAtomicAnimation( startState, NORMAL, config); stateAnim.addListener(new AnimationSuccessListener() { diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java index a19a67c8fc..deb70e0f8b 100644 --- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java +++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java @@ -31,11 +31,12 @@ import android.util.FloatProperty; import androidx.annotation.Nullable; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Launcher; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.touch.PagedOrientationHandler; import com.android.quickstep.LauncherActivityInterface; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.views.RecentsView; @@ -54,11 +55,12 @@ public class AnimatorControllerWithResistance { */ public static final float TWO_BUTTON_EXTRA_DRAG_FACTOR = 0.25f; - private enum RecentsParams { + private enum RecentsResistanceParams { FROM_APP(0.75f, 0.5f, 1f), FROM_OVERVIEW(1f, 0.75f, 0.5f); - RecentsParams(float scaleStartResist, float scaleMaxResist, float translationFactor) { + RecentsResistanceParams(float scaleStartResist, float scaleMaxResist, + float translationFactor) { this.scaleStartResist = scaleStartResist; this.scaleMaxResist = scaleMaxResist; this.translationFactor = translationFactor; @@ -139,9 +141,9 @@ public class AnimatorControllerWithResistance { FloatProperty scaleProperty, TRANSLATION translationTarget, FloatProperty translationProperty) { - PendingAnimation resistAnim = createRecentsResistanceAnim(null, context, - recentsOrientedState, dp, scaleTarget, scaleProperty, translationTarget, - translationProperty, RecentsParams.FROM_APP); + RecentsParams params = new RecentsParams(context, recentsOrientedState, dp, scaleTarget, + scaleProperty, translationTarget, translationProperty); + PendingAnimation resistAnim = createRecentsResistanceAnim(params); AnimatorPlaybackController resistanceController = resistAnim.createPlaybackController(); return new AnimatorControllerWithResistance(normalController, resistanceController); @@ -152,31 +154,30 @@ public class AnimatorControllerWithResistance { * when starting from recents, i.e. {@link #createRecentsResistanceFromOverviewAnim}. */ public static PendingAnimation createRecentsResistanceAnim( - @Nullable PendingAnimation resistAnim, Context context, - RecentsOrientedState recentsOrientedState, DeviceProfile dp, SCALE scaleTarget, - FloatProperty scaleProperty, TRANSLATION translationTarget, - FloatProperty translationProperty, RecentsParams params) { + RecentsParams params) { Rect startRect = new Rect(); - LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, startRect, - recentsOrientedState.getOrientationHandler()); + PagedOrientationHandler orientationHandler = params.recentsOrientedState + .getOrientationHandler(); + LauncherActivityInterface.INSTANCE.calculateTaskSize(params.context, params.dp, startRect, + orientationHandler); long distanceToCover = startRect.bottom; - boolean isTwoButtonMode = SysUINavigationMode.getMode(context) == TWO_BUTTONS; + boolean isTwoButtonMode = SysUINavigationMode.getMode(params.context) == TWO_BUTTONS; if (isTwoButtonMode) { // We can only drag a small distance past overview, not to the top of the screen. distanceToCover = (long) - ((dp.heightPx - startRect.bottom) * TWO_BUTTON_EXTRA_DRAG_FACTOR); - } - if (resistAnim == null) { - resistAnim = new PendingAnimation(distanceToCover * 2); + ((params.dp.heightPx - startRect.bottom) * TWO_BUTTON_EXTRA_DRAG_FACTOR); } + PendingAnimation resistAnim = params.resistAnim != null + ? params.resistAnim + : new PendingAnimation(distanceToCover * 2); PointF pivot = new PointF(); - float fullscreenScale = recentsOrientedState.getFullScreenScaleAndPivot( - startRect, dp, pivot); - float startScale = 1; - float prevScaleRate = (fullscreenScale - startScale) / (dp.heightPx - startRect.bottom); + float fullscreenScale = params.recentsOrientedState.getFullScreenScaleAndPivot( + startRect, params.dp, pivot); + float prevScaleRate = (fullscreenScale - params.startScale) + / (params.dp.heightPx - startRect.bottom); // This is what the scale would be at the end of the drag if we didn't apply resistance. - float endScale = startScale - prevScaleRate * distanceToCover; + float endScale = params.startScale - prevScaleRate * distanceToCover; final TimeInterpolator scaleInterpolator; if (isTwoButtonMode) { // We are bounded by the distance of the drag, so we don't need to apply resistance. @@ -184,9 +185,10 @@ public class AnimatorControllerWithResistance { } else { // Create an interpolator that resists the scale so the scale doesn't get smaller than // RECENTS_SCALE_MAX_RESIST. - float startResist = Utilities.getProgress(params.scaleStartResist , startScale, - endScale); - float maxResist = Utilities.getProgress(params.scaleMaxResist, startScale, endScale); + float startResist = Utilities.getProgress(params.resistanceParams.scaleStartResist, + params.startScale, endScale); + float maxResist = Utilities.getProgress(params.resistanceParams.scaleMaxResist, + params.startScale, endScale); scaleInterpolator = t -> { if (t < startResist) { return t; @@ -196,20 +198,22 @@ public class AnimatorControllerWithResistance { return startResist + resistProgress * (maxResist - startResist); }; } - resistAnim.addFloat(scaleTarget, scaleProperty, startScale, endScale, + resistAnim.addFloat(params.scaleTarget, params.scaleProperty, params.startScale, endScale, scaleInterpolator); if (!isTwoButtonMode) { // Compute where the task view would be based on the end scale, if we didn't translate. RectF endRectF = new RectF(startRect); Matrix temp = new Matrix(); - temp.setScale(params.scaleMaxResist, params.scaleMaxResist, pivot.x, pivot.y); + temp.setScale(params.resistanceParams.scaleMaxResist, + params.resistanceParams.scaleMaxResist, pivot.x, pivot.y); temp.mapRect(endRectF); // Translate such that the task view touches the top of the screen when drag does. - float endTranslation = endRectF.top * recentsOrientedState.getOrientationHandler() - .getSecondaryTranslationDirectionFactor() * params.translationFactor; - resistAnim.addFloat(translationTarget, translationProperty, 0, endTranslation, - RECENTS_TRANSLATE_RESIST_INTERPOLATOR); + float endTranslation = endRectF.top + * orientationHandler.getSecondaryTranslationDirectionFactor() + * params.resistanceParams.translationFactor; + resistAnim.addFloat(params.translationTarget, params.translationProperty, + params.startTranslation, endTranslation, RECENTS_TRANSLATE_RESIST_INTERPOLATOR); } return resistAnim; @@ -220,11 +224,66 @@ public class AnimatorControllerWithResistance { * a RecentsView interaction that started from the overview state. */ public static PendingAnimation createRecentsResistanceFromOverviewAnim( - BaseDraggingActivity activity, @Nullable PendingAnimation resistanceAnim) { - RecentsView recentsView = activity.getOverviewPanel(); - return createRecentsResistanceAnim(resistanceAnim, activity, - recentsView.getPagedViewOrientedState(), activity.getDeviceProfile(), - recentsView, RECENTS_SCALE_PROPERTY, recentsView, TASK_SECONDARY_TRANSLATION, - RecentsParams.FROM_OVERVIEW); + Launcher launcher, @Nullable PendingAnimation resistanceAnim) { + RecentsView recentsView = launcher.getOverviewPanel(); + RecentsParams params = new RecentsParams(launcher, recentsView.getPagedViewOrientedState(), + launcher.getDeviceProfile(), recentsView, RECENTS_SCALE_PROPERTY, recentsView, + TASK_SECONDARY_TRANSLATION) + .setResistAnim(resistanceAnim) + .setResistanceParams(RecentsResistanceParams.FROM_OVERVIEW) + .setStartScale(recentsView.getScaleX()); + return createRecentsResistanceAnim(params); + } + + /** + * Params to compute resistance when scaling/translating recents. + */ + private static class RecentsParams { + // These are all required and can't have default values, hence are final. + public final Context context; + public final RecentsOrientedState recentsOrientedState; + public final DeviceProfile dp; + public final SCALE scaleTarget; + public final FloatProperty scaleProperty; + public final TRANSLATION translationTarget; + public final FloatProperty translationProperty; + + // These are not required, or can have a default value that is generally correct. + @Nullable public PendingAnimation resistAnim = null; + public RecentsResistanceParams resistanceParams = RecentsResistanceParams.FROM_APP; + public float startScale = 1f; + public float startTranslation = 0f; + + private RecentsParams(Context context, RecentsOrientedState recentsOrientedState, + DeviceProfile dp, SCALE scaleTarget, FloatProperty scaleProperty, + TRANSLATION translationTarget, FloatProperty translationProperty) { + this.context = context; + this.recentsOrientedState = recentsOrientedState; + this.dp = dp; + this.scaleTarget = scaleTarget; + this.scaleProperty = scaleProperty; + this.translationTarget = translationTarget; + this.translationProperty = translationProperty; + } + + private RecentsParams setResistAnim(PendingAnimation resistAnim) { + this.resistAnim = resistAnim; + return this; + } + + private RecentsParams setResistanceParams(RecentsResistanceParams resistanceParams) { + this.resistanceParams = resistanceParams; + return this; + } + + private RecentsParams setStartScale(float startScale) { + this.startScale = startScale; + return this; + } + + private RecentsParams setStartTranslation(float startTranslation) { + this.startTranslation = startTranslation; + return this; + } } } From d9d340c87987ba72aaea13efab49b55c7b9fac54 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Sat, 22 Aug 2020 23:05:58 -0700 Subject: [PATCH 05/12] Introduce transparency in all apps for OnDeviceSearch Bug: 165999272 Change-Id: Ic4adf11d030328db47a5b0d1cd915b40902c12de --- res/values/colors.xml | 3 --- .../launcher3/allapps/AllAppsSectionDecorator.java | 9 +++++++-- .../allapps/search/AppsSearchContainerLayout.java | 4 ++-- .../launcher3/allapps/search/AppsSearchPipeline.java | 9 +++++---- .../allapps/search/DefaultAppSearchAlgorithm.java | 5 +++-- src/com/android/launcher3/views/ScrimView.java | 8 +++++++- 6 files changed, 24 insertions(+), 14 deletions(-) diff --git a/res/values/colors.xml b/res/values/colors.xml index fe9717cd7a..f56fbaaace 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -35,9 +35,6 @@ #E0E0E0 - #32c0c0c0 - #40c0c0c0 - #A0C2F9 #6DA1FF #FFFFFFFF diff --git a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java index 6f29e1102c..9534c85cf6 100644 --- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java +++ b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java @@ -22,6 +22,7 @@ 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; @@ -100,6 +101,9 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration { * Handles grouping and drawing of items in the same all apps sections. */ public static class SectionDecorationHandler { + private static final int FILL_ALPHA = (int) (.3f * 255); + private static final int FOCUS_ALPHA = (int) (.8f * 255); + protected RectF mBounds = new RectF(); private final boolean mIsFullWidth; private final float mRadius; @@ -111,8 +115,9 @@ public class AllAppsSectionDecorator extends RecyclerView.ItemDecoration { public SectionDecorationHandler(Context context, boolean isFullWidth) { mIsFullWidth = isFullWidth; - mFillcolor = context.getColor(R.color.all_apps_section_fill); - mFocusColor = context.getColor(R.color.all_apps_section_focused_item); + int endScrim = Themes.getAttrColor(context, R.attr.allAppsScrimColor); + mFillcolor = ColorUtils.setAlphaComponent(endScrim, FILL_ALPHA); + mFocusColor = ColorUtils.setAlphaComponent(endScrim, FOCUS_ALPHA); mRadius = Themes.getDialogCornerRadius(context); } diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java index 6f183eebc0..7518521255 100644 --- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java +++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java @@ -139,8 +139,8 @@ public class AppsSearchContainerLayout extends ExtendedEditText mApps = appsView.getApps(); mAppsView = appsView; mSearchBarController.initialize( - new DefaultAppSearchAlgorithm(LauncherAppState.getInstance(mLauncher)), this, - mLauncher, this, this); + new DefaultAppSearchAlgorithm(mLauncher, LauncherAppState.getInstance(mLauncher)), + this, mLauncher, this, this); } @Override diff --git a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java b/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java index fb3d953bac..6e9a7da4ae 100644 --- a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java +++ b/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java @@ -53,15 +53,16 @@ public class AppsSearchPipeline implements SearchPipeline { private final LauncherAppState mLauncherAppState; private final boolean mHeroSectionSupported; - public AppsSearchPipeline(LauncherAppState launcherAppState) { - this(launcherAppState, true); + public AppsSearchPipeline(Context context, LauncherAppState launcherAppState) { + this(context, launcherAppState, true); } - public AppsSearchPipeline(LauncherAppState launcherAppState, boolean supportsHeroView) { + public AppsSearchPipeline(Context context, LauncherAppState launcherAppState, + boolean supportsHeroView) { mLauncherAppState = launcherAppState; mSearchSectionInfo = new SearchSectionInfo(); mSearchSectionInfo.setDecorationHandler( - new SectionDecorationHandler(launcherAppState.getContext(), true)); + new SectionDecorationHandler(context, true)); mHeroSectionSupported = supportsHeroView; } diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java index 470191c3fc..d757f78523 100644 --- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java +++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java @@ -15,6 +15,7 @@ */ package com.android.launcher3.allapps.search; +import android.content.Context; import android.os.Handler; import com.android.launcher3.LauncherAppState; @@ -30,9 +31,9 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm { protected final Handler mResultHandler; private final AppsSearchPipeline mAppsSearchPipeline; - public DefaultAppSearchAlgorithm(LauncherAppState launcherAppState) { + public DefaultAppSearchAlgorithm(Context context, LauncherAppState launcherAppState) { mResultHandler = new Handler(); - mAppsSearchPipeline = new AppsSearchPipeline(launcherAppState, false); + mAppsSearchPipeline = new AppsSearchPipeline(context, launcherAppState, false); } @Override diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java index 7f0765becd..77cec80fd7 100644 --- a/src/com/android/launcher3/views/ScrimView.java +++ b/src/com/android/launcher3/views/ScrimView.java @@ -32,6 +32,7 @@ import androidx.core.graphics.ColorUtils; import com.android.launcher3.Insettable; import com.android.launcher3.Launcher; import com.android.launcher3.R; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.uioverrides.WallpaperColorInfo; import com.android.launcher3.uioverrides.WallpaperColorInfo.OnChangeListener; import com.android.launcher3.util.Themes; @@ -41,6 +42,7 @@ import com.android.launcher3.util.Themes; */ public class ScrimView extends View implements Insettable, OnChangeListener { + private static final float SCRIM_ALPHA = .75f; protected final T mLauncher; private final WallpaperColorInfo mWallpaperColorInfo; protected final int mEndScrim; @@ -59,7 +61,11 @@ public class ScrimView extends View implements Insettable, O super(context, attrs); mLauncher = Launcher.cast(Launcher.getLauncher(context)); mWallpaperColorInfo = WallpaperColorInfo.INSTANCE.get(context); - mEndScrim = Themes.getAttrColor(context, R.attr.allAppsScrimColor); + int endScrim = Themes.getAttrColor(context, R.attr.allAppsScrimColor); + if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) { + endScrim = ColorUtils.setAlphaComponent(endScrim, (int) (255 * SCRIM_ALPHA)); + } + mEndScrim = endScrim; mIsScrimDark = ColorUtils.calculateLuminance(mEndScrim) < 0.5f; mMaxScrimAlpha = 0.7f; From 6b670d62df460078612900fda49ae902a02e1c69 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Sat, 22 Aug 2020 23:24:43 -0700 Subject: [PATCH 06/12] Good riddance UserEventDispatcher [1/n] Bug: 165675920 Change-Id: I237ed4243e1724b3c370c5660673bb3966bf4811 --- .../appprediction/AllAppsTipView.java | 5 +- .../hybridhotseat/HotseatEduDialog.java | 11 -- .../HotseatPredictionController.java | 6 - .../uioverrides/states/OverviewState.java | 4 - .../NavBarToHomeTouchController.java | 4 +- .../quickstep/OverviewCommandHelper.java | 7 - .../quickstep/TouchInteractionService.java | 18 +-- .../logging/UserEventDispatcherExtension.java | 86 ------------ .../quickstep/views/AllAppsEduView.java | 5 - .../android/quickstep/views/RecentsView.java | 11 -- .../android/quickstep/views/TaskMenuView.java | 5 - .../com/android/quickstep/views/TaskView.java | 4 - .../launcher3/AbstractFloatingView.java | 12 +- .../launcher3/AppWidgetResizeFrame.java | 5 - .../launcher3/BaseDraggingActivity.java | 1 - src/com/android/launcher3/DragSource.java | 3 +- src/com/android/launcher3/Launcher.java | 1 - .../launcher3/SecondaryDropTarget.java | 7 - src/com/android/launcher3/Workspace.java | 21 --- .../allapps/AllAppsContainerView.java | 12 -- .../launcher3/allapps/DiscoveryBounce.java | 5 - .../dragndrop/PinItemDragListener.java | 11 -- src/com/android/launcher3/folder/Folder.java | 33 ----- .../logging/UserEventDispatcher.java | 125 +----------------- .../notification/NotificationInfo.java | 1 - .../popup/PopupContainerWithArrow.java | 26 ---- .../android/launcher3/views/ArrowTipView.java | 4 - .../launcher3/views/FloatingSurfaceView.java | 3 - .../launcher3/views/HeroSearchResultView.java | 8 -- .../android/launcher3/views/ListenerView.java | 5 - .../launcher3/views/OptionsPopupView.java | 5 - src/com/android/launcher3/views/Snackbar.java | 5 - .../android/launcher3/views/WorkEduView.java | 11 -- .../launcher3/widget/BaseWidgetSheet.java | 28 ---- .../launcher3/widget/WidgetsBottomSheet.java | 5 - .../launcher3/widget/WidgetsFullSheet.java | 5 - .../systemui/plugins/UserEventPlugin.java | 34 ----- 37 files changed, 9 insertions(+), 533 deletions(-) delete mode 100644 quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java delete mode 100644 src_plugins/com/android/systemui/plugins/UserEventPlugin.java diff --git a/quickstep/src/com/android/launcher3/appprediction/AllAppsTipView.java b/quickstep/src/com/android/launcher3/appprediction/AllAppsTipView.java index 8477b103a2..98bf483a3d 100644 --- a/quickstep/src/com/android/launcher3/appprediction/AllAppsTipView.java +++ b/quickstep/src/com/android/launcher3/appprediction/AllAppsTipView.java @@ -19,7 +19,6 @@ package com.android.launcher3.appprediction; import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE; import static com.android.launcher3.AbstractFloatingView.TYPE_ON_BOARD_POPUP; import static com.android.launcher3.LauncherState.ALL_APPS; -import static com.android.quickstep.logging.UserEventDispatcherExtension.ALL_APPS_PREDICTION_TIPS; import android.os.UserManager; @@ -31,7 +30,6 @@ import com.android.launcher3.Utilities; import com.android.launcher3.allapps.FloatingHeaderView; import com.android.launcher3.statemanager.StateManager.StateListener; import com.android.launcher3.views.ArrowTipView; -import com.android.systemui.shared.system.LauncherEventUtil; /** * ArrowTip helper aligned just above prediction apps, shown to users that enter all apps for the @@ -57,8 +55,7 @@ public class AllAppsTipView { floatingHeaderView.findFixedRowByType(PredictionRowView.class).getLocationOnScreen(coords); ArrowTipView arrowTipView = new ArrowTipView(launcher).setOnClosedCallback(() -> { launcher.getSharedPrefs().edit().putBoolean(ALL_APPS_TIP_SEEN, true).apply(); - launcher.getUserEventDispatcher().logActionTip(LauncherEventUtil.DISMISS, - ALL_APPS_PREDICTION_TIPS); + // TODO: add log to WW }); arrowTipView.show(launcher.getString(R.string.all_apps_prediction_tip), coords[1]); diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java index 2b3f3953ea..39bf008fc3 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java @@ -40,7 +40,6 @@ import com.android.launcher3.anim.Interpolators; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.uioverrides.PredictedAppIcon; -import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.views.AbstractSlideInView; import java.util.List; @@ -122,16 +121,6 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable handleClose(true); } - @Override - public void logActionCommand(int command) { - // Since this is on-boarding popup, it is not a user controlled action. - } - - @Override - public int getLogContainerType() { - return LauncherLogProto.ContainerType.TIP; - } - @Override protected boolean isOfType(int type) { return (type & TYPE_ON_BOARD_POPUP) != 0; diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index b94e6337d0..1d1296fb5c 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -624,12 +624,6 @@ public class HotseatPredictionController implements DragController.DragListener, //Does nothing } - @Override - public void fillInLogContainerData(ItemInfo childInfo, LauncherLogProto.Target child, - ArrayList parents) { - mHotseat.fillInLogContainerData(childInfo, child, parents); - } - /** * Logs rank info based on current list of predicted items */ diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java index 6ec114e216..bbe7821864 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java @@ -16,7 +16,6 @@ package com.android.launcher3.uioverrides.states; import static com.android.launcher3.anim.Interpolators.DEACCEL_2; -import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import static com.android.quickstep.SysUINavigationMode.hideShelfInTwoButtonLandscape; import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview; @@ -30,7 +29,6 @@ import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Workspace; -import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.util.LayoutUtils; @@ -177,8 +175,6 @@ public class OverviewState extends LauncherState { public void onBackPressed(Launcher launcher) { TaskView taskView = launcher.getOverviewPanel().getRunningTaskView(); if (taskView != null) { - launcher.getUserEventDispatcher().logActionCommand(Action.Command.BACK, - newContainerTarget(ContainerType.OVERVIEW)); taskView.launchTask(true); } else { super.onBackPressed(launcher); diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java index da3c4858a8..60ad4cd66b 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java @@ -229,12 +229,12 @@ public class NavBarToHomeTouchController implements TouchController, () -> onSwipeInteractionCompleted(mEndState)); } if (mStartState != mEndState) { - logStateChange(mStartState.containerType, logAction); + // TODO: add to WW log } AbstractFloatingView topOpenView = AbstractFloatingView.getTopOpenView(mLauncher); if (topOpenView != null) { AbstractFloatingView.closeAllOpenViews(mLauncher); - logStateChange(topOpenView.getLogContainerType(), logAction); + // TODO: add to WW log } ActivityManagerWrapper.getInstance() .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index dca33789e5..365cff576a 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -29,7 +29,6 @@ import android.view.ViewConfiguration; import androidx.annotation.BinderThread; -import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.quickstep.util.ActivityInitListener; @@ -87,12 +86,6 @@ public class OverviewCommandHelper { MAIN_EXECUTOR.execute(new HideRecentsCommand()); } - @BinderThread - public void onTip(int actionType, int viewType) { - MAIN_EXECUTOR.execute(() -> - UserEventDispatcher.newInstance(mContext).logActionTip(actionType, viewType)); - } - private class ShowRecentsCommand extends RecentsActivityCommand { private final boolean mTriggeredFromAltTab; diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index ba0a81fab5..2387692eb9 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -22,7 +22,6 @@ import static android.view.MotionEvent.ACTION_UP; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; -import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.quickstep.GestureState.DEFAULT_STATE; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; @@ -61,7 +60,6 @@ import com.android.launcher3.R; import com.android.launcher3.ResourceUtils; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.provider.RestoreDbTask; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.testing.TestLogging; @@ -141,7 +139,6 @@ public class TouchInteractionService extends Service implements PluginListener implements Launche @CallSuper protected void onDeferredResumed() { logStopAndResume(Action.Command.RESUME); - getUserEventDispatcher().startSession(); // Process any items that were added while Launcher was away. ItemInstallQueue.INSTANCE.get(this) diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java index 56875bb337..2df7f5ad20 100644 --- a/src/com/android/launcher3/SecondaryDropTarget.java +++ b/src/com/android/launcher3/SecondaryDropTarget.java @@ -49,7 +49,6 @@ import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.Themes; import java.net.URISyntaxException; -import java.util.ArrayList; /** * Drop target which provides a secondary option for an item. @@ -339,12 +338,6 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList mDragObject = d; } - @Override - public void fillInLogContainerData(ItemInfo childInfo, Target child, - ArrayList parents) { - mOriginal.fillInLogContainerData(childInfo, child, parents); - } - @Override public void onLauncherResume() { // We use MATCH_UNINSTALLED_PACKAGES as the app can be on SD card as well. diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 6bfd3495e5..383512b128 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -28,7 +28,6 @@ import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.SPRING_LOADED; import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM; import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_OVERLAY; -import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPELEFT; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPERIGHT; @@ -99,7 +98,6 @@ import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.WorkspaceTouchListener; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; -import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.Executors; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSparseArrayMap; @@ -1506,7 +1504,6 @@ public class Workspace extends PagedView .showForIcon((BubbleTextView) child); if (popupContainer != null) { dragOptions.preDragCondition = popupContainer.createPreDragCondition(); - mLauncher.getUserEventDispatcher().resetElapsedContainerMillis("dragging started"); } } @@ -3272,24 +3269,6 @@ public class Workspace extends PagedView return getContext().getString(R.string.workspace_scroll_format, page + 1, nScreens); } - @Override - public void fillInLogContainerData(ItemInfo childInfo, Target child, - ArrayList parents) { - if (childInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT - || childInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) { - getHotseat().fillInLogContainerData(childInfo, child, parents); - return; - } else if (childInfo.container >= 0) { - FolderIcon icon = (FolderIcon) getHomescreenIconByItemId(childInfo.container); - icon.getFolder().fillInLogContainerData(childInfo, child, parents); - return; - } - child.gridX = childInfo.cellX; - child.gridY = childInfo.cellY; - child.pageIndex = getCurrentPage(); - parents.add(newContainerTarget(ContainerType.WORKSPACE)); - } - /** * Used as a workaround to ensure that the AppWidgetService receives the * PACKAGE_ADDED broadcast before updating widgets. diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 0684fe0526..1f515669a6 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -17,7 +17,6 @@ package com.android.launcher3.allapps; import static com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem; import static com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload; -import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED; @@ -62,8 +61,6 @@ import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.keyboard.FocusedItemDecorator; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; -import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.MultiValueAlpha; import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; @@ -71,8 +68,6 @@ import com.android.launcher3.util.Themes; import com.android.launcher3.views.RecyclerViewFastScroller; import com.android.launcher3.views.SpringRelativeLayout; -import java.util.ArrayList; - /** * The all apps view container. */ @@ -354,13 +349,6 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo public void onDropCompleted(View target, DragObject d, boolean success) { } - @Override - public void fillInLogContainerData(ItemInfo childInfo, Target child, - ArrayList parents) { - parents.add(newContainerTarget( - getApps().hasFilter() ? ContainerType.SEARCHRESULT : ContainerType.ALLAPPS)); - } - @Override public void setInsets(Rect insets) { mInsets.set(insets); diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java index b4ff5ea19a..14595ca941 100644 --- a/src/com/android/launcher3/allapps/DiscoveryBounce.java +++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java @@ -115,11 +115,6 @@ public class DiscoveryBounce extends AbstractFloatingView { } } - @Override - public void logActionCommand(int command) { - // Since this is on-boarding popup, it is not a user controlled action. - } - @Override protected boolean isOfType(int type) { return (type & TYPE_DISCOVERY_BOUNCE) != 0; diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java index bf3aa7f7cb..6104d80676 100644 --- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java +++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java @@ -16,7 +16,6 @@ package com.android.launcher3.dragndrop; -import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; import android.annotation.TargetApi; import android.appwidget.AppWidgetManager; @@ -33,15 +32,11 @@ import com.android.launcher3.DragSource; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.PendingAddItemInfo; -import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.widget.PendingAddShortcutInfo; import com.android.launcher3.widget.PendingAddWidgetInfo; import com.android.launcher3.widget.PendingItemDragHelper; import com.android.launcher3.widget.WidgetAddFlowHandler; -import java.util.ArrayList; - /** * {@link DragSource} for handling drop from a different window. This object is initialized * in the source window and is passed on to the Launcher activity as an Intent extra. @@ -106,12 +101,6 @@ public class PinItemDragListener extends BaseItemDragListener { return dragHelper; } - @Override - public void fillInLogContainerData(ItemInfo childInfo, LauncherLogProto.Target child, - ArrayList parents) { - parents.add(newContainerTarget(LauncherLogProto.ContainerType.PINITEM)); - } - @Override protected void postCleanup() { super.postCleanup(); diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index b91d1c3260..547b42aec5 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -19,7 +19,6 @@ package com.android.launcher3.folder; import static android.text.TextUtils.isEmpty; import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY; -import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; import static com.android.launcher3.config.FeatureFlags.ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS; @@ -1481,27 +1480,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo outRect.right += mScrollAreaOffset; } - @Override - public void fillInLogContainerData(ItemInfo childInfo, LauncherLogProto.Target child, - ArrayList targets) { - child.gridX = childInfo.cellX; - child.gridY = childInfo.cellY; - child.pageIndex = mContent.getCurrentPage(); - - LauncherLogProto.Target target = newContainerTarget(LauncherLogProto.ContainerType.FOLDER); - target.pageIndex = mInfo.screenId; - target.gridX = mInfo.cellX; - target.gridY = mInfo.cellY; - targets.add(target); - - // continue to parent - if (mInfo.container == CONTAINER_HOTSEAT) { - mLauncher.getHotseat().fillInLogContainerData(mInfo, target, targets); - } else { - mLauncher.getWorkspace().fillInLogContainerData(mInfo, target, targets); - } - } - private class OnScrollHintListener implements OnAlarmListener { private final DragObject mDragObject; @@ -1589,17 +1567,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo return getOpenView(launcher, TYPE_FOLDER); } - @Override - public void logActionCommand(int command) { - mLauncher.getUserEventDispatcher().logActionCommand( - command, getFolderIcon(), getLogContainerType()); - } - - @Override - public int getLogContainerType() { - return LauncherLogProto.ContainerType.FOLDER; - } - /** * Navigation bar back key or hardware input back key has been issued. */ diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java index 31a81b8164..a40cc263db 100644 --- a/src/com/android/launcher3/logging/UserEventDispatcher.java +++ b/src/com/android/launcher3/logging/UserEventDispatcher.java @@ -19,26 +19,21 @@ package com.android.launcher3.logging; import static com.android.launcher3.logging.LoggerUtils.newAction; import static com.android.launcher3.logging.LoggerUtils.newCommandAction; import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; -import static com.android.launcher3.logging.LoggerUtils.newControlTarget; import static com.android.launcher3.logging.LoggerUtils.newDropTarget; import static com.android.launcher3.logging.LoggerUtils.newItemTarget; import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent; import static com.android.launcher3.logging.LoggerUtils.newTarget; import static com.android.launcher3.logging.LoggerUtils.newTouchAction; -import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType; import static com.android.launcher3.userevent.nano.LauncherLogProto.TipType; import static java.util.Optional.ofNullable; -import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.os.Process; import android.os.SystemClock; -import android.os.UserHandle; import android.util.Log; import android.view.View; @@ -54,7 +49,6 @@ import com.android.launcher3.userevent.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; -import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.LogConfig; import com.android.launcher3.util.ResourceBasedOverride; @@ -101,7 +95,7 @@ public class UserEventDispatcher implements ResourceBasedOverride { * * @return whether container data was added. */ - public boolean fillLogContainer(@Nullable View v, Target child, + private boolean fillLogContainer(@Nullable View v, Target child, @Nullable ArrayList targets) { LogContainerProvider firstParent = StatsLogUtils.getLaunchProviderRecursive(v); if (v == null || !(v.getTag() instanceof ItemInfo) || firstParent == null) { @@ -125,55 +119,6 @@ public class UserEventDispatcher implements ResourceBasedOverride { private boolean mAppOrTaskLaunch; private boolean mPreviousHomeGesture; - // APP_ICON SHORTCUT WIDGET - // -------------------------------------------------------------- - // packageNameHash required optional required - // componentNameHash required required - // intentHash required - // -------------------------------------------------------------- - - @Deprecated - public void logAppLaunch(View v, Intent intent, @Nullable UserHandle userHandle) { - Target itemTarget = newItemTarget(v, mInstantAppResolver); - Action action = newTouchAction(Action.Touch.TAP); - ArrayList targets = makeTargetsList(itemTarget); - if (fillLogContainer(v, itemTarget, targets)) { - onFillInLogContainerData((ItemInfo) v.getTag(), itemTarget, targets); - fillIntentInfo(itemTarget, intent, userHandle); - } - LauncherEvent event = newLauncherEvent(action, targets); - dispatchUserEvent(event, intent); - mAppOrTaskLaunch = true; - } - - /** - * Placeholder method. - */ - public void logActionTip(int actionType, int viewType) { - } - - @Deprecated - public void logTaskLaunchOrDismiss(int action, int direction, int taskIndex, - ComponentKey componentKey) { - LauncherEvent event = newLauncherEvent(newTouchAction(action), // TAP or SWIPE or FLING - newTarget(Target.Type.ITEM)); - if (action == Action.Touch.SWIPE || action == Action.Touch.FLING) { - // Direction DOWN means the task was launched, UP means it was dismissed. - event.action.dir = direction; - } - event.srcTarget[0].itemType = ItemType.TASK; - event.srcTarget[0].pageIndex = taskIndex; - fillComponentInfo(event.srcTarget[0], componentKey.componentName); - dispatchUserEvent(event, null); - mAppOrTaskLaunch = true; - } - - protected void fillIntentInfo(Target target, Intent intent, @Nullable UserHandle userHandle) { - target.intentHash = intent.hashCode(); - target.isWorkApp = userHandle != null && !userHandle.equals(Process.myUserHandle()); - fillComponentInfo(target, intent.getComponent()); - } - private void fillComponentInfo(Target target, ComponentName cn) { if (cn != null) { target.packageNameHash = (mUuidStr + cn.getPackageName()).hashCode(); @@ -181,22 +126,6 @@ public class UserEventDispatcher implements ResourceBasedOverride { } } - public void logNotificationLaunch(View v, PendingIntent intent) { - LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.TAP), - newItemTarget(v, mInstantAppResolver), newTarget(Target.Type.CONTAINER)); - Target itemTarget = newItemTarget(v, mInstantAppResolver); - ArrayList targets = makeTargetsList(itemTarget); - - if (fillLogContainer(v, itemTarget, targets)) { - itemTarget.packageNameHash = (mUuidStr + intent.getCreatorPackage()).hashCode(); - } - dispatchUserEvent(event, null); - } - - public void logActionCommand(int command, Target srcTarget) { - logActionCommand(command, srcTarget, null); - } - public void logActionCommand(int command, int srcContainerType, int dstContainerType) { logActionCommand(command, newContainerTarget(srcContainerType), dstContainerType >= 0 ? newContainerTarget(dstContainerType) : null); @@ -227,25 +156,6 @@ public class UserEventDispatcher implements ResourceBasedOverride { dispatchUserEvent(event, null); } - /** - * TODO: Make this function work when a container view is passed as the 2nd param. - */ - public void logActionCommand(int command, View itemView, int srcContainerType) { - LauncherEvent event = newLauncherEvent(newCommandAction(command), - newItemTarget(itemView, mInstantAppResolver), newTarget(Target.Type.CONTAINER)); - - Target itemTarget = newItemTarget(itemView, mInstantAppResolver); - ArrayList targets = makeTargetsList(itemTarget); - - if (fillLogContainer(itemView, itemTarget, targets)) { - // TODO: Remove the following two lines once fillInLogContainerData can take in a - // container view. - itemTarget.type = Target.Type.CONTAINER; - itemTarget.containerType = srcContainerType; - } - dispatchUserEvent(event, null); - } - public void logActionOnControl(int action, int controlType) { logActionOnControl(action, controlType, null); } @@ -332,7 +242,6 @@ public class UserEventDispatcher implements ResourceBasedOverride { event.srcTarget[0].spanX = downX; event.srcTarget[0].spanY = downY; dispatchUserEvent(event, null); - resetElapsedContainerMillis("state changed"); } public void logActionOnItem(int action, int dir, int itemType) { @@ -386,7 +295,6 @@ public class UserEventDispatcher implements ResourceBasedOverride { ArrayList targets = makeTargetsList(child); fillLogContainer(icon, child, targets); dispatchUserEvent(newLauncherEvent(newTouchAction(Action.Touch.TAP), targets), null); - resetElapsedContainerMillis("deep shortcut open"); } public void logDragNDrop(DropTarget.DragObject dragObj, View dropTargetAsView) { @@ -397,7 +305,7 @@ public class UserEventDispatcher implements ResourceBasedOverride { Target destChild = newItemTarget(dragObj.originalDragInfo, mInstantAppResolver); ArrayList destTargets = makeTargetsList(destChild); - dragObj.dragSource.fillInLogContainerData(dragObj.originalDragInfo, srcChild, srcTargets); + //dragObj.dragSource.fillInLogContainerData(dragObj.originalDragInfo, srcChild, srcTargets); if (dropTargetAsView instanceof LogContainerProvider) { ((LogContainerProvider) dropTargetAsView).fillInLogContainerData(dragObj.dragInfo, destChild, destTargets); @@ -414,35 +322,6 @@ public class UserEventDispatcher implements ResourceBasedOverride { dispatchUserEvent(event, null); } - public void logActionBack(boolean completed, int downX, int downY, boolean isButton, - boolean gestureSwipeLeft, int containerType) { - int actionTouch = isButton ? Action.Touch.TAP : Action.Touch.SWIPE; - Action action = newCommandAction(actionTouch); - action.command = Action.Command.BACK; - action.dir = isButton ? Action.Direction.NONE : - gestureSwipeLeft ? Action.Direction.LEFT : Action.Direction.RIGHT; - Target target = newControlTarget(isButton ? ControlType.BACK_BUTTON : - ControlType.BACK_GESTURE); - target.spanX = downX; - target.spanY = downY; - target.cardinality = completed ? 1 : 0; - LauncherEvent event = newLauncherEvent(action, target, newContainerTarget(containerType)); - - dispatchUserEvent(event, null); - } - - /** - * Currently logs following containers: workspace, allapps, widget tray. - */ - public final void resetElapsedContainerMillis(String reason) { - mElapsedContainerMillis = SystemClock.uptimeMillis(); - if (!IS_VERBOSE) { - return; - } - Log.d(TAG, "resetElapsedContainerMillis reason=" + reason); - - } - public final void startSession() { mSessionStarted = true; mElapsedSessionMillis = SystemClock.uptimeMillis(); diff --git a/src/com/android/launcher3/notification/NotificationInfo.java b/src/com/android/launcher3/notification/NotificationInfo.java index 835f72d5be..80eeb22747 100644 --- a/src/com/android/launcher3/notification/NotificationInfo.java +++ b/src/com/android/launcher3/notification/NotificationInfo.java @@ -106,7 +106,6 @@ public class NotificationInfo implements View.OnClickListener { view, 0, 0, view.getWidth(), view.getHeight()).toBundle(); try { intent.send(null, 0, null, null, null, null, activityOptions); - launcher.getUserEventDispatcher().logNotificationLaunch(view, intent); launcher.getStatsLogManager().logger().withItemInfo(mItemInfo) .log(LAUNCHER_NOTIFICATION_LAUNCH_TAP); } catch (PendingIntent.CanceledException e) { diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 896fb186d4..26b32b8195 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -20,12 +20,9 @@ import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCU import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.Utilities.squaredTouchSlop; import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; -import static com.android.launcher3.notification.NotificationMainView.NOTIFICATION_ITEM_INFO; import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS; import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS; import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; -import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType; -import static com.android.launcher3.userevent.nano.LauncherLogProto.Target; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.animation.AnimatorSet; @@ -147,17 +144,6 @@ public class PopupContainerWithArrow extends Arr return (type & TYPE_ACTION_POPUP) != 0; } - @Override - public void logActionCommand(int command) { - mLauncher.getUserEventDispatcher().logActionCommand( - command, mOriginalIcon, getLogContainerType()); - } - - @Override - public int getLogContainerType() { - return ContainerType.DEEPSHORTCUTS; - } - public OnClickListener getItemClickListener() { return (view) -> { mLauncher.getItemOnClickListener().onClick(view); @@ -495,18 +481,6 @@ public class PopupContainerWithArrow extends Arr } } - @Override - public void fillInLogContainerData(ItemInfo childInfo, Target child, - ArrayList parents) { - if (childInfo == NOTIFICATION_ITEM_INFO) { - child.itemType = ItemType.NOTIFICATION; - } else { - child.itemType = ItemType.DEEPSHORTCUT; - child.rank = childInfo.rank; - } - parents.add(newContainerTarget(ContainerType.DEEPSHORTCUTS)); - } - @Override protected void onCreateCloseAnimation(AnimatorSet anim) { // Animate original icon's text back in. diff --git a/src/com/android/launcher3/views/ArrowTipView.java b/src/com/android/launcher3/views/ArrowTipView.java index b4a6b141ce..1f12a2f8c8 100644 --- a/src/com/android/launcher3/views/ArrowTipView.java +++ b/src/com/android/launcher3/views/ArrowTipView.java @@ -86,10 +86,6 @@ public class ArrowTipView extends AbstractFloatingView { } } - @Override - public void logActionCommand(int command) { - } - @Override protected boolean isOfType(int type) { return (type & TYPE_ON_BOARD_POPUP) != 0; diff --git a/src/com/android/launcher3/views/FloatingSurfaceView.java b/src/com/android/launcher3/views/FloatingSurfaceView.java index 9582232279..011f6de8e2 100644 --- a/src/com/android/launcher3/views/FloatingSurfaceView.java +++ b/src/com/android/launcher3/views/FloatingSurfaceView.java @@ -121,9 +121,6 @@ public class FloatingSurfaceView extends AbstractFloatingView implements launcher.getDragLayer().addView(view); } - @Override - public void logActionCommand(int command) { } - @Override protected boolean isOfType(int type) { return (type & TYPE_ICON_SURFACE) != 0; diff --git a/src/com/android/launcher3/views/HeroSearchResultView.java b/src/com/android/launcher3/views/HeroSearchResultView.java index 10f3c41f35..7b2df80b32 100644 --- a/src/com/android/launcher3/views/HeroSearchResultView.java +++ b/src/com/android/launcher3/views/HeroSearchResultView.java @@ -40,9 +40,7 @@ import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider; import com.android.launcher3.touch.ItemLongClickListener; -import com.android.launcher3.userevent.nano.LauncherLogProto; -import java.util.ArrayList; import java.util.List; /** @@ -118,12 +116,6 @@ public class HeroSearchResultView extends LinearLayout implements DragSource, mBubbleTextView.setIconVisible(true); } - @Override - public void fillInLogContainerData(ItemInfo childInfo, LauncherLogProto.Target child, - ArrayList parents) { - - } - private void setWillDrawIcon(boolean willDraw) { mIconView.setVisibility(willDraw ? View.VISIBLE : View.INVISIBLE); } diff --git a/src/com/android/launcher3/views/ListenerView.java b/src/com/android/launcher3/views/ListenerView.java index 3ef778b575..6e3f0ce690 100644 --- a/src/com/android/launcher3/views/ListenerView.java +++ b/src/com/android/launcher3/views/ListenerView.java @@ -84,11 +84,6 @@ public class ListenerView extends AbstractFloatingView { mIsOpen = false; } - @Override - public void logActionCommand(int command) { - // Users do not interact with FloatingIconView, so there is nothing to log here. - } - @Override protected boolean isOfType(int type) { return (type & TYPE_LISTENER) != 0; diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java index 9ad2331112..3ec20d57a1 100644 --- a/src/com/android/launcher3/views/OptionsPopupView.java +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -107,11 +107,6 @@ public class OptionsPopupView extends ArrowPopup return true; } - @Override - public void logActionCommand(int command) { - // TODO: - } - @Override protected boolean isOfType(int type) { return (type & TYPE_OPTIONS_POPUP) != 0; diff --git a/src/com/android/launcher3/views/Snackbar.java b/src/com/android/launcher3/views/Snackbar.java index 513ce59a62..49fcd2ebde 100644 --- a/src/com/android/launcher3/views/Snackbar.java +++ b/src/com/android/launcher3/views/Snackbar.java @@ -166,11 +166,6 @@ public class Snackbar extends AbstractFloatingView { } } - @Override - public void logActionCommand(int command) { - // TODO - } - @Override protected boolean isOfType(int type) { return (type & TYPE_SNACKBAR) != 0; diff --git a/src/com/android/launcher3/views/WorkEduView.java b/src/com/android/launcher3/views/WorkEduView.java index d35a38fba8..d6737db725 100644 --- a/src/com/android/launcher3/views/WorkEduView.java +++ b/src/com/android/launcher3/views/WorkEduView.java @@ -38,7 +38,6 @@ import com.android.launcher3.allapps.AllAppsPagedView; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.statemanager.StateManager.StateListener; -import com.android.launcher3.userevent.nano.LauncherLogProto; /** * On boarding flow for users right after setting up work profile @@ -88,16 +87,6 @@ public class WorkEduView extends AbstractSlideInView mLauncher.getStateManager().removeStateListener(this); } - @Override - public void logActionCommand(int command) { - // Since this is on-boarding popup, it is not a user controlled action. - } - - @Override - public int getLogContainerType() { - return LauncherLogProto.ContainerType.TIP; - } - @Override protected boolean isOfType(int type) { return (type & TYPE_ON_BOARD_POPUP) != 0; diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java index 3e5113a231..01af96cb33 100644 --- a/src/com/android/launcher3/widget/BaseWidgetSheet.java +++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java @@ -16,7 +16,6 @@ package com.android.launcher3.widget; import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound; -import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; import android.content.Context; import android.graphics.Point; @@ -31,20 +30,15 @@ import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.dragndrop.DragOptions; -import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.popup.PopupDataProvider; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.uioverrides.WallpaperColorInfo; -import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; -import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.Themes; import com.android.launcher3.views.AbstractSlideInView; -import java.util.ArrayList; - /** * Base class for various widgets popup */ @@ -149,28 +143,6 @@ abstract class BaseWidgetSheet extends AbstractSlideInView isSheetDark ? SystemUiController.FLAG_DARK_NAV : SystemUiController.FLAG_LIGHT_NAV); } - @Override - public void fillInLogContainerData(ItemInfo childInfo, Target child, - ArrayList parents) { - Target target = newContainerTarget(ContainerType.WIDGETS); - target.cardinality = getElementsRowCount(); - parents.add(target); - } - - @Override - public final void logActionCommand(int command) { - Target target = newContainerTarget(getLogContainerType()); - target.cardinality = getElementsRowCount(); - mLauncher.getUserEventDispatcher().logActionCommand(command, target); - } - - @Override - public int getLogContainerType() { - return ContainerType.WIDGETS; - } - - protected abstract int getElementsRowCount(); - protected SystemUiController getSystemUiController() { return mLauncher.getSystemUiController(); } diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java index 30be7a673d..3585a1814b 100644 --- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java +++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java @@ -179,11 +179,6 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable { setPadding(leftInset, getPaddingTop(), rightInset, bottomInset); } - @Override - protected int getElementsRowCount() { - return 1; - } - @Override protected Pair getAccessibilityTarget() { return Pair.create(findViewById(R.id.title), getContext().getString( diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java index 68a3ec51ee..4c8c339998 100644 --- a/src/com/android/launcher3/widget/WidgetsFullSheet.java +++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java @@ -242,11 +242,6 @@ public class WidgetsFullSheet extends BaseWidgetSheet return launcher.findViewById(R.id.widgets_list_view); } - @Override - protected int getElementsRowCount() { - return mAdapter.getItemCount(); - } - @Override public void addHintCloseAnim( float distanceToMove, Interpolator interpolator, PendingAnimation target) { diff --git a/src_plugins/com/android/systemui/plugins/UserEventPlugin.java b/src_plugins/com/android/systemui/plugins/UserEventPlugin.java deleted file mode 100644 index 0e3664ae3f..0000000000 --- a/src_plugins/com/android/systemui/plugins/UserEventPlugin.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2019 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.systemui.plugins; - -import com.android.systemui.plugins.annotations.ProvidesInterface; - -/** - * Implement this plugin interface to access user event log on the device for prototype purpose. - * NOTE: plugin is for internal prototype only and is not visible in production environment. - */ -@ProvidesInterface(action = UserEventPlugin.ACTION, version = UserEventPlugin.VERSION) -public interface UserEventPlugin extends Plugin { - String ACTION = "com.android.launcher3.action.PLUGIN_USER_EVENT_LOG"; - int VERSION = 1; - - /** - * Callback to be triggered whenever an user event occurs. - */ - void onUserEvent(Object event); -} From 77e29775a9e9fd98a3905130dad0c15ead9edfa4 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Tue, 25 Aug 2020 00:53:48 -0700 Subject: [PATCH 07/12] Fix Robolectric test breakage Bug: 166204002 Change-Id: I9c54c6230756dbb5fe8bdcb37ba51165d20bb815 --- src/com/android/launcher3/Launcher.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 0970dae479..52583d413c 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -925,6 +925,7 @@ public class Launcher extends StatefulActivity implements Launche private void logStopAndResume(int command) { + if (mPendingExecutor != null) return; int pageIndex = mWorkspace.isOverlayShown() ? -1 : mWorkspace.getCurrentPage(); int containerType = mStateManager.getState().containerType; From a2d6a91be904335767aee36844aeced5c84efc47 Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Sun, 23 Aug 2020 15:58:39 -0700 Subject: [PATCH 08/12] Support settings search in AllApps [preview attached to BR] Bug: 166044087 Test: Manual Change-Id: I997fc1c7e2e2c500f64858df9ccea4911e05d649 --- Android.mk | 1 + res/layout/search_result_settings_row.xml | 57 ++++++++++ res/layout/search_result_slice.xml | 19 ++++ .../launcher3/allapps/AllAppsGridAdapter.java | 59 +++++++++- .../allapps/AllAppsSectionDecorator.java | 4 +- .../views/SearchSettingsRowView.java | 102 ++++++++++++++++++ 6 files changed, 235 insertions(+), 7 deletions(-) create mode 100644 res/layout/search_result_settings_row.xml create mode 100644 res/layout/search_result_slice.xml create mode 100644 src/com/android/launcher3/views/SearchSettingsRowView.java diff --git a/Android.mk b/Android.mk index 752b530ab0..25f5412d21 100644 --- a/Android.mk +++ b/Android.mk @@ -28,6 +28,7 @@ LOCAL_STATIC_ANDROID_LIBRARIES := \ androidx.recyclerview_recyclerview \ androidx.dynamicanimation_dynamicanimation \ androidx.preference_preference \ + androidx.slice_slice-view \ iconloader_base LOCAL_STATIC_JAVA_LIBRARIES := \ diff --git a/res/layout/search_result_settings_row.xml b/res/layout/search_result_settings_row.xml new file mode 100644 index 0000000000..19daf346e2 --- /dev/null +++ b/res/layout/search_result_settings_row.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/search_result_slice.xml b/res/layout/search_result_slice.xml new file mode 100644 index 0000000000..ea1d49a56d --- /dev/null +++ b/res/layout/search_result_slice.xml @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java index c61f01f206..da161ac1cc 100644 --- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java +++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java @@ -20,6 +20,7 @@ import static com.android.launcher3.touch.ItemLongClickListener.INSTANCE_ALL_APP import android.content.Context; import android.content.Intent; import android.content.res.Resources; +import android.net.Uri; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; @@ -30,18 +31,27 @@ import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.widget.TextView; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.view.accessibility.AccessibilityEventCompat; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; import androidx.core.view.accessibility.AccessibilityRecordCompat; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LifecycleRegistry; +import androidx.lifecycle.LiveData; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.slice.Slice; +import androidx.slice.widget.SliceLiveData; +import androidx.slice.widget.SliceView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.BubbleTextView; import com.android.launcher3.R; import com.android.launcher3.allapps.search.AllAppsSearchBarController.PayloadResultHandler; import com.android.launcher3.allapps.search.SearchSectionInfo; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.util.PackageManagerHelper; @@ -50,7 +60,9 @@ import java.util.List; /** * The grid view adapter of all the apps. */ -public class AllAppsGridAdapter extends RecyclerView.Adapter { +public class AllAppsGridAdapter extends + RecyclerView.Adapter implements + LifecycleOwner { public static final String TAG = "AppsGridAdapter"; @@ -71,12 +83,18 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter Play load Type */ public static class AdapterItemWithPayload extends AdapterItem { @@ -310,6 +331,12 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter) mApps.getAdapterItems().get(position)) + .getPayload(); + try { + LiveData liveData = SliceLiveData.fromUri(mLauncher, uri); + liveData.observe(this::getLifecycle, sliceView); + } catch (Exception ignored) { + } + break; case VIEW_TYPE_SEARCH_CORPUS_TITLE: - case DETAIL_ROW_WITH_BUTTON: + case VIEW_TYPE_SEARCH_ROW_WITH_BUTTON: case VIEW_TYPE_SEARCH_HERO_APP: + case VIEW_TYPE_SEARCH_ROW: PayloadResultHandler payloadResultView = (PayloadResultHandler) holder.itemView; payloadResultView.applyAdapterInfo( (AdapterItemWithPayload) mApps.getAdapterItems().get(position)); @@ -451,4 +495,9 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter { + + private TextView mTitleView; + private TextView mDescriptionView; + private TextView mBreadcrumbsView; + private Intent mIntent; + + public SearchSettingsRowView(@NonNull Context context) { + super(context); + } + + public SearchSettingsRowView(@NonNull Context context, + @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public SearchSettingsRowView(@NonNull Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mTitleView = findViewById(R.id.title); + mDescriptionView = findViewById(R.id.description); + mBreadcrumbsView = findViewById(R.id.breadcrumbs); + setOnClickListener(this); + } + + @Override + public void applyAdapterInfo( + AllAppsGridAdapter.AdapterItemWithPayload adapterItemWithPayload) { + Bundle bundle = adapterItemWithPayload.getPayload(); + mIntent = bundle.getParcelable("intent"); + showIfAvailable(mTitleView, bundle.getString("title")); + showIfAvailable(mDescriptionView, bundle.getString("description")); + ArrayList breadcrumbs = bundle.getStringArrayList("breadcrumbs"); + //TODO: implement RTL friendly breadcrumbs view + showIfAvailable(mBreadcrumbsView, breadcrumbs != null + ? String.join(" > ", breadcrumbs) : null); + adapterItemWithPayload.setSelectionHandler(() -> onClick(this)); + } + + private void showIfAvailable(TextView view, @Nullable String string) { + if (TextUtils.isEmpty(string)) { + view.setVisibility(GONE); + } else { + view.setVisibility(VISIBLE); + view.setText(string); + } + } + + @Override + public void onClick(View view) { + if (mIntent == null) return; + // TODO: create ItemInfo object and then use it to call startActivityForResult for proper + // WW logging + Launcher launcher = Launcher.getLauncher(view.getContext()); + launcher.startActivityForResult(mIntent, 0); + } +} From 8acdb23e64a7e48ad7f15dac22816e7bf95292a9 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Tue, 25 Aug 2020 18:26:29 -0700 Subject: [PATCH 09/12] Init rotationTouchHelper before NavModeChange listener NavModeChange listener relies on rotationTouchHelper to be non-null, but we instantiate rotationTouchHelper after nav mode changes are fired off. Fixes: 166303464 Change-Id: Iab92d0fe0ee842d907d7226dfd9ca599e7729675 --- .../src/com/android/quickstep/TouchInteractionService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 2387692eb9..5b4a2395cd 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -249,10 +249,10 @@ public class TouchInteractionService extends Service implements PluginListener Date: Sun, 23 Aug 2020 21:56:07 -0700 Subject: [PATCH 10/12] Handle AppSearch in plugin + Use AppSearchPipeline as a fallback if plugin times out Bug: 166058597 Test: Manual Change-Id: I96a38e412fd08f47475d2bc37bff34b86538ea12 --- src/com/android/launcher3/BubbleTextView.java | 17 +++-- .../allapps/search/AppsSearchPipeline.java | 64 +------------------ .../search/DefaultAppSearchAlgorithm.java | 2 +- .../android/launcher3/model/AllAppsList.java | 2 +- .../launcher3/views/HeroSearchResultView.java | 10 +-- .../launcher3/widget/WidgetsListAdapter.java | 22 +++---- 6 files changed, 32 insertions(+), 85 deletions(-) diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 55d5de758a..06bb263f23 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -79,7 +79,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, private static final int DISPLAY_FOLDER = 2; private static final int DISPLAY_HERO_APP = 5; - private static final int[] STATE_PRESSED = new int[] {android.R.attr.state_pressed}; + private static final int[] STATE_PRESSED = new int[]{android.R.attr.state_pressed}; private final PointF mTranslationForReorderBounce = new PointF(0, 0); private final PointF mTranslationForReorderPreview = new PointF(0, 0); @@ -280,7 +280,10 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, applyDotState(info, false /* animate */); } - public void applyFromPackageItemInfo(PackageItemInfo info) { + /** + * Apply label and tag using a generic {@link ItemInfoWithIcon} + */ + public void applyFromItemInfoWithIcon(ItemInfoWithIcon info) { applyIconAndLabel(info); // We don't need to check the info since it's not a WorkspaceItemInfo super.setTag(info); @@ -407,12 +410,14 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, /** * Draws the notification dot in the top right corner of the icon bounds. + * * @param canvas The canvas to draw to. */ protected void drawDotIfNecessary(Canvas canvas) { if (!mForceHideDot && (hasDot() || mDotParams.scale > 0)) { getIconBounds(mDotParams.iconBounds); - Utilities.scaleRectAboutCenter(mDotParams.iconBounds, IconShape.getNormalizationScale()); + Utilities.scaleRectAboutCenter(mDotParams.iconBounds, + IconShape.getNormalizationScale()); final int scrollX = getScrollX(); final int scrollY = getScrollY(); canvas.translate(scrollX, scrollY); @@ -507,6 +512,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, /** * Creates an animator to fade the text in or out. + * * @param fadeIn Whether the text should fade in or fade out. */ public ObjectAnimator createTextAlphaAnimator(boolean fadeIn) { @@ -663,7 +669,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, applyFromWorkspaceItem((WorkspaceItemInfo) info); mActivity.invalidateParent(info); } else if (info instanceof PackageItemInfo) { - applyFromPackageItemInfo((PackageItemInfo) info); + applyFromItemInfoWithIcon((PackageItemInfo) info); } mDisableRelayout = false; @@ -761,7 +767,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, public SafeCloseable prepareDrawDragView() { resetIconScale(); setForceHideDot(true); - return () -> { }; + return () -> { + }; } private void resetIconScale() { diff --git a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java b/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java index 6e9a7da4ae..dc9c1559d5 100644 --- a/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java +++ b/src/com/android/launcher3/allapps/search/AppsSearchPipeline.java @@ -15,26 +15,15 @@ */ package com.android.launcher3.allapps.search; -import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS; -import static com.android.launcher3.allapps.AllAppsGridAdapter.VIEW_TYPE_SEARCH_HERO_APP; - import android.content.Context; -import android.content.pm.ShortcutInfo; - -import androidx.annotation.WorkerThread; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.allapps.AllAppsGridAdapter; import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem; import com.android.launcher3.allapps.AllAppsSectionDecorator.SectionDecorationHandler; -import com.android.launcher3.icons.IconCache; 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.model.data.WorkspaceItemInfo; -import com.android.launcher3.popup.PopupPopulator; -import com.android.launcher3.shortcuts.ShortcutRequest; import java.util.ArrayList; import java.util.List; @@ -46,64 +35,28 @@ import java.util.function.Consumer; public class AppsSearchPipeline implements SearchPipeline { private static final int MAX_RESULTS_COUNT = 5; - private static final int MAX_HERO_SECTION_COUNT = 2; - private static final int MAX_SHORTCUTS_COUNT = 2; private final SearchSectionInfo mSearchSectionInfo; private final LauncherAppState mLauncherAppState; - private final boolean mHeroSectionSupported; public AppsSearchPipeline(Context context, LauncherAppState launcherAppState) { - this(context, launcherAppState, true); - } - - public AppsSearchPipeline(Context context, LauncherAppState launcherAppState, - boolean supportsHeroView) { mLauncherAppState = launcherAppState; mSearchSectionInfo = new SearchSectionInfo(); mSearchSectionInfo.setDecorationHandler( new SectionDecorationHandler(context, true)); - mHeroSectionSupported = supportsHeroView; } @Override - @WorkerThread public void performSearch(String query, Consumer> callback) { mLauncherAppState.getModel().enqueueModelUpdateTask(new BaseModelUpdateTask() { @Override public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) { List matchingResults = getTitleMatchResult(apps.data, query); - if (mHeroSectionSupported && matchingResults.size() <= MAX_HERO_SECTION_COUNT) { - callback.accept(getHeroAdapterItems(app.getContext(), matchingResults)); - } else { - callback.accept(getAdapterItems(matchingResults)); - } + callback.accept(getAdapterItems(matchingResults)); } }); } - /** - * Returns MAX_SHORTCUTS_COUNT shortcuts from local cache - * TODO: Shortcuts should be ranked based on relevancy - */ - private ArrayList getShortcutInfos(Context context, AppInfo appInfo) { - List shortcuts = new ShortcutRequest(context, appInfo.user) - .withContainer(appInfo.getTargetComponent()) - .query(ShortcutRequest.PUBLISHED); - shortcuts = PopupPopulator.sortAndFilterShortcuts(shortcuts, null); - IconCache cache = LauncherAppState.getInstance(context).getIconCache(); - ArrayList shortcutItems = new ArrayList<>(); - for (int i = 0; i < shortcuts.size() && i < MAX_SHORTCUTS_COUNT; i++) { - final ShortcutInfo shortcut = shortcuts.get(i); - final WorkspaceItemInfo si = new WorkspaceItemInfo(shortcut, context); - cache.getUnbadgedShortcutIcon(si, shortcut); - si.rank = i; - si.container = CONTAINER_SHORTCUTS; - shortcutItems.add(si); - } - return shortcutItems; - } - /** * Filters {@link AppInfo}s matching specified query */ @@ -122,21 +75,6 @@ public class AppsSearchPipeline implements SearchPipeline { return result; } - private ArrayList getHeroAdapterItems(Context context, List apps) { - ArrayList adapterItems = new ArrayList<>(); - for (int i = 0; i < apps.size(); i++) { - //hero app - AppInfo appInfo = apps.get(i); - ArrayList shortcuts = getShortcutInfos(context, appInfo); - AdapterItem adapterItem = new AllAppsGridAdapter.AdapterItemWithPayload(shortcuts, - VIEW_TYPE_SEARCH_HERO_APP); - adapterItem.appInfo = appInfo; - adapterItem.searchSectionInfo = mSearchSectionInfo; - adapterItems.add(adapterItem); - } - return adapterItems; - } - private ArrayList getAdapterItems(List matchingApps) { ArrayList items = new ArrayList<>(); for (int i = 0; i < matchingApps.size() && i < MAX_RESULTS_COUNT; i++) { diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java index d757f78523..5ed7de54fa 100644 --- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java +++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java @@ -33,7 +33,7 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm { public DefaultAppSearchAlgorithm(Context context, LauncherAppState launcherAppState) { mResultHandler = new Handler(); - mAppsSearchPipeline = new AppsSearchPipeline(context, launcherAppState, false); + mAppsSearchPipeline = new AppsSearchPipeline(context, launcherAppState); } @Override diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java index eb5d1068ac..2695e66591 100644 --- a/src/com/android/launcher3/model/AllAppsList.java +++ b/src/com/android/launcher3/model/AllAppsList.java @@ -305,7 +305,7 @@ public class AllAppsList { * * @return the corresponding AppInfo or null */ - private @Nullable AppInfo findAppInfo(@NonNull ComponentName componentName, + public @Nullable AppInfo findAppInfo(@NonNull ComponentName componentName, @NonNull UserHandle user) { for (AppInfo info: data) { if (componentName.equals(info.componentName) && user.equals(info.user)) { diff --git a/src/com/android/launcher3/views/HeroSearchResultView.java b/src/com/android/launcher3/views/HeroSearchResultView.java index 7b2df80b32..761ef0d639 100644 --- a/src/com/android/launcher3/views/HeroSearchResultView.java +++ b/src/com/android/launcher3/views/HeroSearchResultView.java @@ -37,6 +37,7 @@ import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.graphics.DragPreviewProvider; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider; import com.android.launcher3.touch.ItemLongClickListener; @@ -47,8 +48,9 @@ import java.util.List; * A view representing a high confidence app search result that includes shortcuts */ public class HeroSearchResultView extends LinearLayout implements DragSource, - AllAppsSearchBarController.PayloadResultHandler> { + AllAppsSearchBarController.PayloadResultHandler> { + public static final int MAX_SHORTCUTS_COUNT = 2; BubbleTextView mBubbleTextView; View mIconView; BubbleTextView[] mDeepShortcutTextViews = new BubbleTextView[2]; @@ -97,15 +99,15 @@ public class HeroSearchResultView extends LinearLayout implements DragSource, * Apply {@link ItemInfo} for appIcon and shortcut Icons */ @Override - public void applyAdapterInfo(AdapterItemWithPayload> adapterItem) { + public void applyAdapterInfo(AdapterItemWithPayload> adapterItem) { mBubbleTextView.applyFromApplicationInfo(adapterItem.appInfo); mIconView.setBackground(mBubbleTextView.getIcon()); mIconView.setTag(adapterItem.appInfo); - List shorcutInfos = adapterItem.getPayload(); + List shorcutInfos = adapterItem.getPayload(); for (int i = 0; i < mDeepShortcutTextViews.length; i++) { mDeepShortcutTextViews[i].setVisibility(shorcutInfos.size() > i ? VISIBLE : GONE); if (i < shorcutInfos.size()) { - mDeepShortcutTextViews[i].applyFromWorkspaceItem(shorcutInfos.get(i)); + mDeepShortcutTextViews[i].applyFromItemInfoWithIcon(shorcutInfos.get(i)); } } } diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java index a45521dee7..5bf96906be 100644 --- a/src/com/android/launcher3/widget/WidgetsListAdapter.java +++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java @@ -23,9 +23,12 @@ import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; -import com.android.launcher3.icons.IconCache; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView.Adapter; + import com.android.launcher3.R; import com.android.launcher3.WidgetPreviewLoader; +import com.android.launcher3.icons.IconCache; import com.android.launcher3.model.WidgetItem; import com.android.launcher3.util.LabelComparator; @@ -34,9 +37,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerView.Adapter; - /** * List view adapter for the widget tray. * @@ -128,7 +128,7 @@ public class WidgetsListAdapter extends Adapter { int childCount = row.getChildCount(); if (expectedChildCount > childCount) { - for (int i = childCount ; i < expectedChildCount; i++) { + for (int i = childCount; i < expectedChildCount; i++) { if ((i & 1) == 1) { // Add a divider for odd index mLayoutInflater.inflate(R.layout.widget_list_divider, row); @@ -144,24 +144,24 @@ public class WidgetsListAdapter extends Adapter { } } } else if (expectedChildCount < childCount) { - for (int i = expectedChildCount ; i < childCount; i++) { + for (int i = expectedChildCount; i < childCount; i++) { row.getChildAt(i).setVisibility(View.GONE); } } // Bind the views in the application info section. - holder.title.applyFromPackageItemInfo(entry.pkgItem); + holder.title.applyFromItemInfoWithIcon(entry.pkgItem); // Bind the view in the widget horizontal tray region. - for (int i=0; i < infoList.size(); i++) { - WidgetCell widget = (WidgetCell) row.getChildAt(2*i); + for (int i = 0; i < infoList.size(); i++) { + WidgetCell widget = (WidgetCell) row.getChildAt(2 * i); widget.applyFromCellItem(infoList.get(i), mWidgetPreviewLoader); widget.setApplyBitmapDeferred(mApplyBitmapDeferred); widget.ensurePreview(); widget.setVisibility(View.VISIBLE); if (i > 0) { - row.getChildAt(2*i - 1).setVisibility(View.VISIBLE); + row.getChildAt(2 * i - 1).setVisibility(View.VISIBLE); } } } @@ -185,7 +185,7 @@ public class WidgetsListAdapter extends Adapter { @Override public void onViewRecycled(WidgetsRowViewHolder holder) { int total = holder.cellContainer.getChildCount(); - for (int i = 0; i < total; i+=2) { + for (int i = 0; i < total; i += 2) { WidgetCell widget = (WidgetCell) holder.cellContainer.getChildAt(i); widget.clear(); } From d4d2a73b67324dc1b5312dd0e93f6222619aa260 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Sat, 22 Aug 2020 02:09:42 -0700 Subject: [PATCH 11/12] Removing MultiHashMap and using java-streams instead This makes it easier to choose different collection implementations Change-Id: Ic44e128b7478fcbbb1b546027685e058945af3f9 --- .../launcher3/model/FirstScreenBroadcast.java | 43 +++--- .../android/launcher3/model/LoaderTask.java | 7 +- .../android/launcher3/model/ModelUtils.java | 10 +- .../model/SdCardAvailableReceiver.java | 26 ++-- .../launcher3/model/ShortcutsChangedTask.java | 62 ++++---- .../launcher3/popup/PopupDataProvider.java | 20 +-- .../launcher3/popup/SystemShortcut.java | 2 +- .../launcher3/util/ItemInfoMatcher.java | 3 +- .../android/launcher3/util/MultiHashMap.java | 52 ------- .../android/launcher3/model/WidgetsModel.java | 144 +++++++++--------- 10 files changed, 150 insertions(+), 219 deletions(-) delete mode 100644 src/com/android/launcher3/util/MultiHashMap.java diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java index 5112304fb8..70d1b481e6 100644 --- a/src/com/android/launcher3/model/FirstScreenBroadcast.java +++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java @@ -17,25 +17,30 @@ package com.android.launcher3.model; import static android.os.Process.myUserHandle; +import static com.android.launcher3.pm.InstallSessionHelper.getUserHandle; + +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.mapping; + import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInstaller.SessionInfo; +import android.os.UserHandle; import android.util.Log; import com.android.launcher3.LauncherSettings; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; -import com.android.launcher3.util.MultiHashMap; import com.android.launcher3.util.PackageUserKey; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; /** * Helper class to send broadcasts to package installers that have: @@ -61,26 +66,10 @@ public class FirstScreenBroadcast { private static final String VERIFICATION_TOKEN_EXTRA = "verificationToken"; - private final MultiHashMap mPackagesForInstaller; + private final HashMap mSessionInfoForPackage; public FirstScreenBroadcast(HashMap sessionInfoForPackage) { - mPackagesForInstaller = getPackagesForInstaller(sessionInfoForPackage); - } - - /** - * @return Map where the key is the package name of the installer, and the value is a list - * of packages with active sessions for that installer. - */ - private MultiHashMap getPackagesForInstaller( - HashMap sessionInfoForPackage) { - MultiHashMap packagesForInstaller = new MultiHashMap<>(); - for (Map.Entry entry : sessionInfoForPackage.entrySet()) { - if (myUserHandle().equals(entry.getKey().mUser)) { - packagesForInstaller.addToList(entry.getValue().getInstallerPackageName(), - entry.getKey().mPackageName); - } - } - return packagesForInstaller; + mSessionInfoForPackage = sessionInfoForPackage; } /** @@ -88,9 +77,15 @@ public class FirstScreenBroadcast { * first screen. */ public void sendBroadcasts(Context context, List firstScreenItems) { - for (Map.Entry> entry : mPackagesForInstaller.entrySet()) { - sendBroadcastToInstaller(context, entry.getKey(), entry.getValue(), firstScreenItems); - } + UserHandle myUser = myUserHandle(); + mSessionInfoForPackage + .values() + .stream() + .filter(info -> myUser.equals(getUserHandle(info))) + .collect(groupingBy(SessionInfo::getInstallerPackageName, + mapping(SessionInfo::getAppPackageName, Collectors.toSet()))) + .forEach((installer, packages) -> + sendBroadcastToInstaller(context, installer, packages, firstScreenItems)); } /** @@ -99,7 +94,7 @@ public class FirstScreenBroadcast { * @param firstScreenItems List of items on the first screen. */ private void sendBroadcastToInstaller(Context context, String installerPackageName, - List packages, List firstScreenItems) { + Set packages, List firstScreenItems) { Set folderItems = new HashSet<>(); Set workspaceItems = new HashSet<>(); Set hotseatItems = new HashSet<>(); diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 983ec0c176..a9e385fcc2 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -81,7 +81,6 @@ import com.android.launcher3.shortcuts.ShortcutRequest.QueryResult; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.IOUtils; import com.android.launcher3.util.LooperIdleLock; -import com.android.launcher3.util.MultiHashMap; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.TraceHelper; @@ -90,8 +89,10 @@ import com.android.launcher3.widget.WidgetManagerHelper; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.CancellationException; /** @@ -302,7 +303,7 @@ public class LoaderTask implements Runnable { final PackageManagerHelper pmHelper = new PackageManagerHelper(context); final boolean isSafeMode = pmHelper.isSafeMode(); final boolean isSdCardReady = Utilities.isBootCompleted(); - final MultiHashMap pendingPackages = new MultiHashMap<>(); + final Set pendingPackages = new HashSet<>(); boolean clearDb = false; try { @@ -483,7 +484,7 @@ public class LoaderTask implements Runnable { // SdCard is not ready yet. Package might get available, // once it is ready. Log.d(TAG, "Missing pkg, will check later: " + targetPkg); - pendingPackages.addToList(c.user, targetPkg); + pendingPackages.add(new PackageUserKey(targetPkg, c.user)); // Add the icon on the workspace anyway. allowMissingTarget = true; } else { diff --git a/src/com/android/launcher3/model/ModelUtils.java b/src/com/android/launcher3/model/ModelUtils.java index a8cc9ad3f3..9b5fac8734 100644 --- a/src/com/android/launcher3/model/ModelUtils.java +++ b/src/com/android/launcher3/model/ModelUtils.java @@ -36,8 +36,8 @@ import com.android.launcher3.util.IntSet; import java.util.ArrayList; import java.util.Collections; -import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.stream.IntStream; /** @@ -56,13 +56,7 @@ public class ModelUtils { ArrayList currentScreenItems, ArrayList otherScreenItems) { // Purge any null ItemInfos - Iterator iter = allWorkspaceItems.iterator(); - while (iter.hasNext()) { - ItemInfo i = iter.next(); - if (i == null) { - iter.remove(); - } - } + allWorkspaceItems.removeIf(Objects::isNull); // Order the set of items by their containers first, this allows use to walk through the // list sequentially, build up a list of containers that are in the specified screen, // as well as all items in those containers. diff --git a/src/com/android/launcher3/model/SdCardAvailableReceiver.java b/src/com/android/launcher3/model/SdCardAvailableReceiver.java index eb3cb52796..3798575f8a 100644 --- a/src/com/android/launcher3/model/SdCardAvailableReceiver.java +++ b/src/com/android/launcher3/model/SdCardAvailableReceiver.java @@ -24,12 +24,11 @@ import android.os.UserHandle; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel; -import com.android.launcher3.util.MultiHashMap; import com.android.launcher3.util.PackageManagerHelper; +import com.android.launcher3.util.PackageUserKey; import java.util.ArrayList; -import java.util.HashSet; -import java.util.Map.Entry; +import java.util.Set; /** * Helper class to re-query app status when SD-card becomes available. @@ -42,10 +41,9 @@ public class SdCardAvailableReceiver extends BroadcastReceiver { private final LauncherModel mModel; private final Context mContext; - private final MultiHashMap mPackages; + private final Set mPackages; - public SdCardAvailableReceiver(LauncherAppState app, - MultiHashMap packages) { + public SdCardAvailableReceiver(LauncherAppState app, Set packages) { mModel = app.getModel(); mContext = app.getContext(); mPackages = packages; @@ -55,19 +53,17 @@ public class SdCardAvailableReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { final LauncherApps launcherApps = context.getSystemService(LauncherApps.class); final PackageManagerHelper pmHelper = new PackageManagerHelper(context); - for (Entry> entry : mPackages.entrySet()) { - UserHandle user = entry.getKey(); + for (PackageUserKey puk : mPackages) { + UserHandle user = puk.mUser; final ArrayList packagesRemoved = new ArrayList<>(); final ArrayList packagesUnavailable = new ArrayList<>(); - for (String pkg : new HashSet<>(entry.getValue())) { - if (!launcherApps.isPackageEnabled(pkg, user)) { - if (pmHelper.isAppOnSdcard(pkg, user)) { - packagesUnavailable.add(pkg); - } else { - packagesRemoved.add(pkg); - } + if (!launcherApps.isPackageEnabled(puk.mPackageName, user)) { + if (pmHelper.isAppOnSdcard(puk.mPackageName, user)) { + packagesUnavailable.add(puk.mPackageName); + } else { + packagesRemoved.add(puk.mPackageName); } } if (!packagesRemoved.isEmpty()) { diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java index 88006ba6fb..6fedad1c9d 100644 --- a/src/com/android/launcher3/model/ShortcutsChangedTask.java +++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java @@ -25,11 +25,12 @@ import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.util.ItemInfoMatcher; -import com.android.launcher3.util.MultiHashMap; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; /** * Handles changes due to shortcut manager updates (deep shortcut changes) @@ -53,54 +54,53 @@ public class ShortcutsChangedTask extends BaseModelUpdateTask { public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) { final Context context = app.getContext(); // Find WorkspaceItemInfo's that have changed on the workspace. - HashSet removedKeys = new HashSet<>(); - MultiHashMap keyToShortcutInfo = new MultiHashMap<>(); - HashSet allIds = new HashSet<>(); + ArrayList matchingWorkspaceItems = new ArrayList<>(); synchronized (dataModel) { dataModel.forAllWorkspaceItemInfos(mUser, si -> { if ((si.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) && mPackageName.equals(si.getIntent().getPackage())) { - keyToShortcutInfo.addToList(ShortcutKey.fromItemInfo(si), si); - allIds.add(si.getDeepShortcutId()); + matchingWorkspaceItems.add(si); } }); } - final ArrayList updatedWorkspaceItemInfos = new ArrayList<>(); - if (!keyToShortcutInfo.isEmpty()) { + if (!matchingWorkspaceItems.isEmpty()) { // Update the workspace to reflect the changes to updated shortcuts residing on it. + List allLauncherKnownIds = matchingWorkspaceItems.stream() + .map(WorkspaceItemInfo::getDeepShortcutId) + .distinct() + .collect(Collectors.toList()); List shortcuts = new ShortcutRequest(context, mUser) - .forPackage(mPackageName, new ArrayList<>(allIds)) + .forPackage(mPackageName, allLauncherKnownIds) .query(ShortcutRequest.ALL); + + Set nonPinnedIds = new HashSet<>(allLauncherKnownIds); + ArrayList updatedWorkspaceItemInfos = new ArrayList<>(); for (ShortcutInfo fullDetails : shortcuts) { - ShortcutKey key = ShortcutKey.fromInfo(fullDetails); - List workspaceItemInfos = keyToShortcutInfo.remove(key); if (!fullDetails.isPinned()) { - // The shortcut was previously pinned but is no longer, so remove it from - // the workspace and our pinned shortcut counts. - // Note that we put this check here, after querying for full details, - // because there's a possible race condition between pinning and - // receiving this callback. - removedKeys.add(key); continue; } - for (final WorkspaceItemInfo workspaceItemInfo : workspaceItemInfos) { - workspaceItemInfo.updateFromDeepShortcutInfo(fullDetails, context); - app.getIconCache().getShortcutIcon(workspaceItemInfo, fullDetails); - updatedWorkspaceItemInfos.add(workspaceItemInfo); - } + + String sid = fullDetails.getId(); + nonPinnedIds.remove(sid); + matchingWorkspaceItems + .stream() + .filter(itemInfo -> sid.equals(itemInfo.getDeepShortcutId())) + .forEach(workspaceItemInfo -> { + workspaceItemInfo.updateFromDeepShortcutInfo(fullDetails, context); + app.getIconCache().getShortcutIcon(workspaceItemInfo, fullDetails); + updatedWorkspaceItemInfos.add(workspaceItemInfo); + }); } - } - // If there are still entries in keyToShortcutInfo, that means that - // the corresponding shortcuts weren't passed in onShortcutsChanged(). This - // means they were cleared, so we remove and unpin them now. - removedKeys.addAll(keyToShortcutInfo.keySet()); - - bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos); - if (!keyToShortcutInfo.isEmpty()) { - deleteAndBindComponentsRemoved(ItemInfoMatcher.ofShortcutKeys(removedKeys)); + bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos); + if (!nonPinnedIds.isEmpty()) { + deleteAndBindComponentsRemoved(ItemInfoMatcher.ofShortcutKeys( + nonPinnedIds.stream() + .map(id -> new ShortcutKey(mPackageName, mUser, id)) + .collect(Collectors.toSet()))); + } } if (mUpdateIdMap) { diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java index 5a5f66832d..76048ba610 100644 --- a/src/com/android/launcher3/popup/PopupDataProvider.java +++ b/src/com/android/launcher3/popup/PopupDataProvider.java @@ -38,7 +38,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -202,20 +201,11 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan } public List getWidgetsForPackageUser(PackageUserKey packageUserKey) { - for (WidgetListRowEntry entry : mAllWidgets) { - if (entry.pkgItem.packageName.equals(packageUserKey.mPackageName)) { - ArrayList widgets = new ArrayList<>(entry.widgets); - // Remove widgets not associated with the correct user. - Iterator iterator = widgets.iterator(); - while (iterator.hasNext()) { - if (!iterator.next().user.equals(packageUserKey.mUser)) { - iterator.remove(); - } - } - return widgets.isEmpty() ? null : widgets; - } - } - return null; + return mAllWidgets.stream() + .filter(row -> row.pkgItem.packageName.equals(packageUserKey.mPackageName)) + .flatMap(row -> row.widgets.stream()) + .filter(widget -> packageUserKey.mUser.equals(widget.user)) + .collect(Collectors.toList()); } /** diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index 79984889ef..81302ac1f7 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -99,7 +99,7 @@ public abstract class SystemShortcut extends Ite final List widgets = launcher.getPopupDataProvider().getWidgetsForPackageUser(new PackageUserKey( itemInfo.getTargetComponent().getPackageName(), itemInfo.user)); - if (widgets == null) { + if (widgets.isEmpty()) { return null; } return new Widgets(launcher, itemInfo); diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java index e98af35563..d26bb5779e 100644 --- a/src/com/android/launcher3/util/ItemInfoMatcher.java +++ b/src/com/android/launcher3/util/ItemInfoMatcher.java @@ -27,6 +27,7 @@ import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.shortcuts.ShortcutKey; import java.util.HashSet; +import java.util.Set; /** * A utility class to check for {@link ItemInfo} @@ -99,7 +100,7 @@ public interface ItemInfoMatcher { return (info, cn) -> packageNames.contains(cn.getPackageName()) && info.user.equals(user); } - static ItemInfoMatcher ofShortcutKeys(HashSet keys) { + static ItemInfoMatcher ofShortcutKeys(Set keys) { return (info, cn) -> info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT && keys.contains(ShortcutKey.fromItemInfo(info)); } diff --git a/src/com/android/launcher3/util/MultiHashMap.java b/src/com/android/launcher3/util/MultiHashMap.java deleted file mode 100644 index b7275c1f76..0000000000 --- a/src/com/android/launcher3/util/MultiHashMap.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2016 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.util; - -import java.util.ArrayList; -import java.util.HashMap; - -/** - * A utility map from keys to an ArrayList of values. - */ -public class MultiHashMap extends HashMap> { - - public MultiHashMap() { } - - public MultiHashMap(int size) { - super(size); - } - - public void addToList(K key, V value) { - ArrayList list = get(key); - if (list == null) { - list = new ArrayList<>(); - list.add(value); - put(key, list); - } else { - list.add(value); - } - } - - @Override - public MultiHashMap clone() { - MultiHashMap map = new MultiHashMap<>(size()); - for (Entry> entry : entrySet()) { - map.put(entry.getKey(), new ArrayList(entry.getValue())); - } - return map; - } -} diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java index a64df62c3b..34ebbac59a 100644 --- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java +++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java @@ -26,7 +26,6 @@ import com.android.launcher3.icons.ComponentWithLabelAndIcon; import com.android.launcher3.icons.IconCache; import com.android.launcher3.model.data.PackageItemInfo; import com.android.launcher3.pm.ShortcutConfigActivityInfo; -import com.android.launcher3.util.MultiHashMap; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.Preconditions; import com.android.launcher3.widget.WidgetItemComparator; @@ -36,11 +35,12 @@ import com.android.launcher3.widget.WidgetManagerHelper; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; /** * Widgets data model that is used by the adapters of the widget views and controllers. @@ -57,9 +57,7 @@ public class WidgetsModel { private static final boolean DEBUG = false; /* Map of widgets and shortcuts that are tracked per package. */ - private final MultiHashMap mWidgetsList = new MultiHashMap<>(); - - private AppFilter mAppFilter; + private final Map> mWidgetsList = new HashMap<>(); /** * Returns a list of {@link WidgetListRowEntry}. All {@link WidgetItem} in a single row @@ -74,8 +72,9 @@ public class WidgetsModel { AlphabeticIndexCompat indexer = new AlphabeticIndexCompat(context); WidgetItemComparator widgetComparator = new WidgetItemComparator(); - for (Map.Entry> entry : mWidgetsList.entrySet()) { - WidgetListRowEntry row = new WidgetListRowEntry(entry.getKey(), entry.getValue()); + for (Map.Entry> entry : mWidgetsList.entrySet()) { + WidgetListRowEntry row = new WidgetListRowEntry( + entry.getKey(), new ArrayList<>(entry.getValue())); row.titleSectionName = (row.pkgItem.title == null) ? "" : indexer.computeSectionName(row.pkgItem.title); Collections.sort(row.widgets, widgetComparator); @@ -146,77 +145,42 @@ public class WidgetsModel { if (packageUser == null) { mWidgetsList.clear(); } else { - // Only clear the widgets for the given package/user. - PackageItemInfo packageItem = null; - for (PackageItemInfo item : mWidgetsList.keySet()) { - if (item.packageName.equals(packageUser.mPackageName)) { - packageItem = item; - break; - } - } + PackageItemInfo packageItem = mWidgetsList.keySet() + .stream() + .filter(item -> item.packageName.equals(packageUser.mPackageName)) + .findFirst() + .orElse(null); if (packageItem != null) { // We want to preserve the user that was on the packageItem previously, // so add it to tmpPackageItemInfos here to avoid creating a new entry. tmpPackageItemInfos.put(packageItem.packageName, packageItem); - Iterator widgetItemIterator = mWidgetsList.get(packageItem).iterator(); - while (widgetItemIterator.hasNext()) { - WidgetItem nextWidget = widgetItemIterator.next(); - if (nextWidget.componentName.getPackageName().equals(packageUser.mPackageName) - && nextWidget.user.equals(packageUser.mUser)) { - widgetItemIterator.remove(); - } - } + // Add the widgets for other users in the rawList as it only contains widgets for + // packageUser + List otherUserItems = mWidgetsList.remove(packageItem); + otherUserItems.removeIf(w -> w.user.equals(packageUser.mUser)); + rawWidgetsShortcuts.addAll(otherUserItems); } } - InvariantDeviceProfile idp = app.getInvariantDeviceProfile(); UserHandle myUser = Process.myUserHandle(); // add and update. - for (WidgetItem item : rawWidgetsShortcuts) { - if (item.widgetInfo != null) { - if ((item.widgetInfo.getWidgetFeatures() & WIDGET_FEATURE_HIDE_FROM_PICKER) != 0) { - // Widget is hidden from picker - continue; - } - - // Ensure that all widgets we show can be added on a workspace of this size - int minSpanX = Math.min(item.widgetInfo.spanX, item.widgetInfo.minSpanX); - int minSpanY = Math.min(item.widgetInfo.spanY, item.widgetInfo.minSpanY); - if (minSpanX > idp.numColumns || minSpanY > idp.numRows) { - if (DEBUG) { - Log.d(TAG, String.format( - "Widget %s : (%d X %d) can't fit on this device", - item.componentName, minSpanX, minSpanY)); + mWidgetsList.putAll(rawWidgetsShortcuts.stream() + .filter(new WidgetValidityCheck(app)) + .collect(Collectors.groupingBy(item -> { + String packageName = item.componentName.getPackageName(); + PackageItemInfo pInfo = tmpPackageItemInfos.get(packageName); + if (pInfo == null) { + pInfo = new PackageItemInfo(packageName); + pInfo.user = item.user; + tmpPackageItemInfos.put(packageName, pInfo); + } else if (!myUser.equals(pInfo.user)) { + // Keep updating the user, until we get the primary user. + pInfo.user = item.user; } - continue; - } - } - - if (mAppFilter == null) { - mAppFilter = AppFilter.newInstance(app.getContext()); - } - if (!mAppFilter.shouldShowApp(item.componentName)) { - if (DEBUG) { - Log.d(TAG, String.format("%s is filtered and not added to the widget tray.", - item.componentName)); - } - continue; - } - - String packageName = item.componentName.getPackageName(); - PackageItemInfo pInfo = tmpPackageItemInfos.get(packageName); - if (pInfo == null) { - pInfo = new PackageItemInfo(packageName); - pInfo.user = item.user; - tmpPackageItemInfos.put(packageName, pInfo); - } else if (!myUser.equals(pInfo.user)) { - // Keep updating the user, until we get the primary user. - pInfo.user = item.user; - } - mWidgetsList.addToList(pInfo, item); - } + return pInfo; + }))); // Update each package entry IconCache iconCache = app.getIconCache(); @@ -227,9 +191,9 @@ public class WidgetsModel { public void onPackageIconsUpdated(Set packageNames, UserHandle user, LauncherAppState app) { - for (Entry> entry : mWidgetsList.entrySet()) { + for (Entry> entry : mWidgetsList.entrySet()) { if (packageNames.contains(entry.getKey().packageName)) { - ArrayList items = entry.getValue(); + List items = entry.getValue(); int count = items.size(); for (int i = 0; i < count; i++) { WidgetItem item = items.get(i); @@ -249,7 +213,7 @@ public class WidgetsModel { public WidgetItem getWidgetProviderInfoByProviderName( ComponentName providerName) { - ArrayList widgetsList = mWidgetsList.get( + List widgetsList = mWidgetsList.get( new PackageItemInfo(providerName.getPackageName())); if (widgetsList == null) { return null; @@ -262,4 +226,46 @@ public class WidgetsModel { } return null; } + + private static class WidgetValidityCheck implements Predicate { + + private final InvariantDeviceProfile mIdp; + private final AppFilter mAppFilter; + + WidgetValidityCheck(LauncherAppState app) { + mIdp = app.getInvariantDeviceProfile(); + mAppFilter = AppFilter.newInstance(app.getContext()); + } + + @Override + public boolean test(WidgetItem item) { + if (item.widgetInfo != null) { + if ((item.widgetInfo.getWidgetFeatures() & WIDGET_FEATURE_HIDE_FROM_PICKER) != 0) { + // Widget is hidden from picker + return false; + } + + // Ensure that all widgets we show can be added on a workspace of this size + int minSpanX = Math.min(item.widgetInfo.spanX, item.widgetInfo.minSpanX); + int minSpanY = Math.min(item.widgetInfo.spanY, item.widgetInfo.minSpanY); + if (minSpanX > mIdp.numColumns || minSpanY > mIdp.numRows) { + if (DEBUG) { + Log.d(TAG, String.format( + "Widget %s : (%d X %d) can't fit on this device", + item.componentName, minSpanX, minSpanY)); + } + return false; + } + } + if (!mAppFilter.shouldShowApp(item.componentName)) { + if (DEBUG) { + Log.d(TAG, String.format("%s is filtered and not added to the widget tray.", + item.componentName)); + } + return false; + } + + return true; + } + } } \ No newline at end of file From fee2b25b9c0df85190fe01d870c84392d210964a Mon Sep 17 00:00:00 2001 From: Sreyas Date: Thu, 27 Aug 2020 15:48:00 -0700 Subject: [PATCH 12/12] Implementing TouchDelegate to make full chip clickable. Bug: 166376182 Tested: Manual Change-Id: I36b2559908fbf7ab6a863fb6e550a88b5374aefa --- .../android/quickstep/views/RecentsView.java | 10 ++---- .../com/android/quickstep/views/TaskView.java | 36 +++++++++++++++++-- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index 1d17f5af70..7111b69dba 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -79,7 +79,6 @@ import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; -import android.view.TouchDelegate; import android.view.View; import android.view.ViewDebug; import android.view.ViewGroup; @@ -700,12 +699,9 @@ public abstract class RecentsView extends PagedView super.onTouchEvent(ev); TaskView taskView = getCurrentPageTaskView(); - if (taskView != null) { - TouchDelegate mChildTouchDelegate = taskView.getIconTouchDelegate(ev); - if (mChildTouchDelegate != null && mChildTouchDelegate.onTouchEvent(ev)) { - // Keep consuming events to pass to delegate - return true; - } + if (taskView != null && taskView.offerTouchToChildren(ev)) { + // Keep consuming events to pass to delegate + return true; } final int x = (int) ev.getX(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java index 2058a7f375..65cadd6350 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java @@ -135,6 +135,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { * delegated bounds only to be updated. */ private TransformingTouchDelegate mIconTouchDelegate; + private TransformingTouchDelegate mChipTouchDelegate; private static final List SYSTEM_GESTURE_EXCLUSION_RECT = Collections.singletonList(new Rect()); @@ -200,6 +201,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { private View mContextualChipWrapper; private View mContextualChip; private final float[] mIconCenterCoords = new float[2]; + private final float[] mChipCenterCoords = new float[2]; public TaskView(Context context) { this(context, null); @@ -263,11 +265,22 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { mIconTouchDelegate = new TransformingTouchDelegate(mIconView); } - public TouchDelegate getIconTouchDelegate(MotionEvent event) { + /** + * Whether the taskview should take the touch event from parent. Events passed to children + * that might require special handling. + */ + public boolean offerTouchToChildren(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { computeAndSetIconTouchDelegate(); + computeAndSetChipTouchDelegate(); } - return mIconTouchDelegate; + if (mIconTouchDelegate != null && mIconTouchDelegate.onTouchEvent(event)) { + return true; + } + if (mChipTouchDelegate != null && mChipTouchDelegate.onTouchEvent(event)) { + return true; + } + return false; } private void computeAndSetIconTouchDelegate() { @@ -282,6 +295,23 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { (int) (mIconCenterCoords[1] + iconHalfSize)); } + private void computeAndSetChipTouchDelegate() { + if (mContextualChipWrapper != null) { + float chipHalfWidth = mContextualChipWrapper.getWidth() / 2f; + float chipHalfHeight = mContextualChipWrapper.getHeight() / 2f; + mChipCenterCoords[0] = chipHalfWidth; + mChipCenterCoords[1] = chipHalfHeight; + getDescendantCoordRelativeToAncestor(mContextualChipWrapper, mActivity.getDragLayer(), + mChipCenterCoords, + false); + mChipTouchDelegate.setBounds( + (int) (mChipCenterCoords[0] - chipHalfWidth), + (int) (mChipCenterCoords[1] - chipHalfHeight), + (int) (mChipCenterCoords[0] + chipHalfWidth), + (int) (mChipCenterCoords[1] + chipHalfHeight)); + } + } + /** * The modalness of this view is how it should be displayed when it is shown on its own in the * modal state of overview. @@ -725,6 +755,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { mContextualChip.animate().scaleX(1f).scaleY(1f).setDuration(50); } if (mContextualChipWrapper != null) { + mChipTouchDelegate = new TransformingTouchDelegate(mContextualChipWrapper); mContextualChipWrapper.animate().alpha(1f).setDuration(50); } } @@ -746,6 +777,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { View oldContextualChipWrapper = mContextualChipWrapper; mContextualChipWrapper = null; mContextualChip = null; + mChipTouchDelegate = null; return oldContextualChipWrapper; }