From 099945b075c57ce04f554286a41ca05189ef6f63 Mon Sep 17 00:00:00 2001 From: Brian Isganitis Date: Mon, 31 Jan 2022 18:15:00 -0500 Subject: [PATCH] Add predictions row to taskbar all apps. - We need to listen to DeviceProfile changes in case the number of columns changes in the grid. I made an interface/mixin separate from ActivityContext to avoid polutting the latter with too many things. I also applied this change to existing taskbar A-Z grid. - Added all apps visited count to onboarding preferences for only showing "All Apps" label in place of divider 20 times. Label is also tracked on taskbar side and should be kept in sync. Test: Manual Fix: 216843395 Bug: 174174514 Change-Id: I97aa91397c334123626caf18251f19e17c7104fb --- quickstep/res/layout/taskbar_all_apps.xml | 2 + .../appprediction/AppsDividerView.java | 70 ++++--------------- .../appprediction/PredictionRowView.java | 59 +++++++++------- .../taskbar/TaskbarActivityContext.java | 35 +++++++++- .../taskbar/TaskbarAllAppsViewController.java | 33 +++++++-- .../taskbar/TaskbarModelCallbacks.java | 11 ++- .../uioverrides/QuickstepLauncher.java | 9 +-- .../util/QuickstepOnboardingPrefs.java | 20 ++++++ src/com/android/launcher3/BaseActivity.java | 24 +++---- src/com/android/launcher3/DeviceProfile.java | 30 ++++++++ src/com/android/launcher3/Launcher.java | 14 ++-- .../allapps/ActivityAllAppsContainerView.java | 1 - .../allapps/BaseAllAppsContainerView.java | 14 ++-- .../launcher3/allapps/FloatingHeaderView.java | 10 +-- .../launcher3/util/OnboardingPrefs.java | 14 ++-- .../launcher3/views/ActivityContext.java | 11 +++ 16 files changed, 224 insertions(+), 133 deletions(-) diff --git a/quickstep/res/layout/taskbar_all_apps.xml b/quickstep/res/layout/taskbar_all_apps.xml index 1ad20cc79f..11d75c7d9b 100644 --- a/quickstep/res/layout/taskbar_all_apps.xml +++ b/quickstep/res/layout/taskbar_all_apps.xml @@ -46,6 +46,8 @@ android:paddingTop="@dimen/all_apps_header_top_padding" android:orientation="vertical"> + + diff --git a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java index 4f987d2eb9..d37e530c61 100644 --- a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java +++ b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java @@ -16,7 +16,7 @@ package com.android.launcher3.appprediction; -import static com.android.launcher3.LauncherState.ALL_APPS; +import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT; import android.annotation.TargetApi; import android.content.Context; @@ -34,23 +34,17 @@ import androidx.annotation.ColorInt; import androidx.core.content.ContextCompat; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.allapps.FloatingHeaderRow; import com.android.launcher3.allapps.FloatingHeaderView; -import com.android.launcher3.statemanager.StateManager.StateListener; import com.android.launcher3.util.Themes; +import com.android.launcher3.views.ActivityContext; /** * A view which shows a horizontal divider */ @TargetApi(Build.VERSION_CODES.O) -public class AppsDividerView extends View implements StateListener, - FloatingHeaderRow { - - private static final String ALL_APPS_VISITED_COUNT = "launcher.all_apps_visited_count"; - private static final int SHOW_ALL_APPS_LABEL_ON_ALL_APPS_VISITED_COUNT = 20; +public class AppsDividerView extends View implements FloatingHeaderRow { public enum DividerType { NONE, @@ -58,7 +52,6 @@ public class AppsDividerView extends View implements StateListener + extends LinearLayout implements OnDeviceProfileChangeListener, FloatingHeaderRow { - private final Launcher mLauncher; + private final T mActivityContext; private int mNumPredictedAppsPerRow; // Helper to drawing the focus indicator. @@ -64,12 +64,10 @@ public class PredictionRowView extends LinearLayout implements private final List mPredictedApps = new ArrayList<>(); private FloatingHeaderView mParent; - private boolean mScrolledOut; private boolean mPredictionsEnabled = false; - - @Nullable - private List mPendingPredictedItems; + private @Nullable List mPendingPredictedItems; + private OnLongClickListener mOnIconLongClickListener = ItemLongClickListener.INSTANCE_ALL_APPS; public PredictionRowView(@NonNull Context context) { this(context, null); @@ -80,9 +78,9 @@ public class PredictionRowView extends LinearLayout implements setOrientation(LinearLayout.HORIZONTAL); mFocusHelper = new SimpleFocusIndicatorHelper(this); - mLauncher = Launcher.getLauncher(context); - mLauncher.addOnDeviceProfileChangeListener(this); - mNumPredictedAppsPerRow = mLauncher.getDeviceProfile().numShownAllAppsColumns; + mActivityContext = ActivityContext.lookupContext(context); + mActivityContext.addOnDeviceProfileChangeListener(this); + mNumPredictedAppsPerRow = mActivityContext.getDeviceProfile().numShownAllAppsColumns; updateVisibility(); } @@ -97,11 +95,11 @@ public class PredictionRowView extends LinearLayout implements private void updateVisibility() { setVisibility(mPredictionsEnabled ? VISIBLE : GONE); - if (mLauncher.getAppsView() != null) { + if (mActivityContext.getAppsView() != null) { if (mPredictionsEnabled) { - mLauncher.getAppsView().getAppsStore().registerIconContainer(this); + mActivityContext.getAppsView().getAppsStore().registerIconContainer(this); } else { - mLauncher.getAppsView().getAppsStore().unregisterIconContainer(this); + mActivityContext.getAppsView().getAppsStore().unregisterIconContainer(this); } } } @@ -120,9 +118,9 @@ public class PredictionRowView extends LinearLayout implements @Override public int getExpectedHeight() { - return getVisibility() == GONE ? 0 : - Launcher.getLauncher(getContext()).getDeviceProfile().allAppsCellHeightPx - + getPaddingTop() + getPaddingBottom(); + return getVisibility() == GONE ? 0 + : mActivityContext.getDeviceProfile().allAppsCellHeightPx + getPaddingTop() + + getPaddingBottom(); } @Override @@ -158,13 +156,12 @@ public class PredictionRowView extends LinearLayout implements */ public void setPredictedApps(List items) { if (!FeatureFlags.ENABLE_APP_PREDICTIONS_WHILE_VISIBLE.get() - && !mLauncher.isWorkspaceLoading() + && !mActivityContext.isBindingItems() && isShown() && getWindowVisibility() == View.VISIBLE) { mPendingPredictedItems = items; return; } - applyPredictedApps(items); } @@ -177,6 +174,15 @@ public class PredictionRowView extends LinearLayout implements applyPredictionApps(); } + /** + * Sets the long click listener for predictions for any future predictions. + * + * Existing predictions in the container are not updated with this new callback. + */ + public void setOnIconLongClickListener(OnLongClickListener onIconLongClickListener) { + mOnIconLongClickListener = onIconLongClickListener; + } + @Override public void onDeviceProfileChanged(DeviceProfile dp) { mNumPredictedAppsPerRow = dp.numShownAllAppsColumns; @@ -189,18 +195,18 @@ public class PredictionRowView extends LinearLayout implements while (getChildCount() > mNumPredictedAppsPerRow) { removeViewAt(0); } - LayoutInflater inflater = mLauncher.getAppsView().getLayoutInflater(); + LayoutInflater inflater = mActivityContext.getAppsView().getLayoutInflater(); while (getChildCount() < mNumPredictedAppsPerRow) { BubbleTextView icon = (BubbleTextView) inflater.inflate( R.layout.all_apps_icon, this, false); - icon.setOnClickListener(ItemClickHandler.INSTANCE); - icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_ALL_APPS); + icon.setOnClickListener(mActivityContext.getItemOnClickListener()); + icon.setOnLongClickListener(mOnIconLongClickListener); icon.setLongPressTimeoutFactor(1f); icon.setOnFocusChangeListener(mFocusHelper); LayoutParams lp = (LayoutParams) icon.getLayoutParams(); // Ensure the all apps icon height matches the workspace icons in portrait mode. - lp.height = mLauncher.getDeviceProfile().allAppsCellHeightPx; + lp.height = mActivityContext.getDeviceProfile().allAppsCellHeightPx; lp.width = 0; lp.weight = 1; addView(icon); @@ -223,7 +229,6 @@ public class PredictionRowView extends LinearLayout implements boolean predictionsEnabled = predictionCount > 0; if (predictionsEnabled != mPredictionsEnabled) { mPredictionsEnabled = predictionsEnabled; - mLauncher.reapplyUi(false /* cancelCurrentAnimation */); updateVisibility(); } mParent.onHeightUpdated(); @@ -237,11 +242,10 @@ public class PredictionRowView extends LinearLayout implements @Override public void setVerticalScroll(int scroll, boolean isScrolledOut) { - mScrolledOut = isScrolledOut; if (!isScrolledOut) { setTranslationY(scroll); } - setAlpha(mScrolledOut ? 0 : 1); + setAlpha(isScrolledOut ? 0 : 1); if (getVisibility() != GONE) { AlphaUpdateListener.updateVisibility(this); } @@ -263,6 +267,7 @@ public class PredictionRowView extends LinearLayout implements return getChildAt(0); } + @Override public void onVisibilityAggregated(boolean isVisible) { super.onVisibilityAggregated(isVisible); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index abe8aad277..70f078032a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -58,8 +58,11 @@ import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.DeviceProfile.DeviceProfileListenable; +import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.dot.DotInfo; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; @@ -70,6 +73,7 @@ import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.PopupDataProvider; import com.android.launcher3.touch.ItemClickHandler; +import com.android.launcher3.util.OnboardingPrefs; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.SettingsCache; import com.android.launcher3.util.Themes; @@ -85,13 +89,16 @@ import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; /** * The {@link ActivityContext} with which we inflate Taskbar-related Views. This allows UI elements * that are used by both Launcher and Taskbar (such as Folder) to reference a generic * ActivityContext and BaseDragLayer instead of the Launcher activity and its DragLayer. */ -public class TaskbarActivityContext extends ContextThemeWrapper implements ActivityContext { +public class TaskbarActivityContext extends ContextThemeWrapper implements ActivityContext, + DeviceProfileListenable { private static final boolean ENABLE_THREE_BUTTON_TASKBAR = SystemProperties.getBoolean("persist.debug.taskbar_three_button", false); @@ -103,6 +110,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ private final TaskbarDragLayer mDragLayer; private final TaskbarAllAppsContainerView mAppsView; private final TaskbarControllers mControllers; + private final List mDPChangeListeners = new ArrayList<>(); private DeviceProfile mDeviceProfile; @@ -123,14 +131,17 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ private boolean mIsDestroyed = false; // The flag to know if the window is excluded from magnification region computation. private boolean mIsExcludeFromMagnificationRegion = false; + private boolean mBindingItems = false; private final TaskbarShortcutMenuAccessibilityDelegate mAccessibilityDelegate; + private final OnboardingPrefs mOnboardingPrefs; public TaskbarActivityContext(Context windowContext, DeviceProfile dp, TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider unfoldTransitionProgressProvider) { super(windowContext, Themes.getActivityThemeRes(windowContext)); mDeviceProfile = dp; + mOnboardingPrefs = new OnboardingPrefs<>(this, Utilities.getPrefs(this)); mNavMode = SysUINavigationMode.getMode(windowContext); mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode", @@ -227,6 +238,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ public void updateDeviceProfile(DeviceProfile dp) { mDeviceProfile = dp; updateIconSize(getResources()); + dispatchDeviceProfileChanged(); } private void updateIconSize(Resources resources) { @@ -298,6 +310,11 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ return mDeviceProfile; } + @Override + public List getOnDeviceProfileChangeListeners() { + return mDPChangeListeners; + } + @Override public Rect getFolderBoundingBox() { return mControllers.taskbarDragLayerController.getFolderBoundingBox(); @@ -388,6 +405,20 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ return mAccessibilityDelegate; } + @Override + public OnboardingPrefs getOnboardingPrefs() { + return mOnboardingPrefs; + } + + @Override + public boolean isBindingItems() { + return mBindingItems; + } + + public void setBindingItems(boolean bindingItems) { + mBindingItems = bindingItems; + } + /** * Sets a new data-source for this taskbar instance */ @@ -730,6 +761,8 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ "%s\tmIsUserSetupComplete=%b", prefix, mIsUserSetupComplete)); pw.println(String.format( "%s\tmWindowLayoutParams.height=%dpx", prefix, mWindowLayoutParams.height)); + pw.println(String.format( + "%s\tmBindInProgress=%b", prefix, mBindingItems)); mControllers.dumpLogs(prefix + "\t", pw); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsViewController.java index 62125feae6..2670200342 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsViewController.java @@ -15,8 +15,15 @@ */ package com.android.launcher3.taskbar; +import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT; + +import com.android.launcher3.appprediction.AppsDividerView; +import com.android.launcher3.appprediction.PredictionRowView; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.AppInfo; +import com.android.launcher3.model.data.ItemInfo; + +import java.util.List; /** Handles the {@link TaskbarAllAppsContainerView} initialization and updates. */ public final class TaskbarAllAppsViewController { @@ -40,6 +47,9 @@ public final class TaskbarAllAppsViewController { mAppsView.setOnIconLongClickListener( controllers.taskbarDragController::startDragOnLongClick); + mAppsView.getFloatingHeaderView().findFixedRowByType( + PredictionRowView.class).setOnIconLongClickListener( + controllers.taskbarDragController::startDragOnLongClick); } /** Binds the current {@link AppInfo} instances to the {@link TaskbarAllAppsContainerView}. */ @@ -49,11 +59,26 @@ public final class TaskbarAllAppsViewController { } } - /** Opens the {@link TaskbarAllAppsContainerView}. */ - public void show() { + /** Binds the current app predictions to all apps {@link PredictionRowView}. */ + public void setPredictedApps(List predictedApps) { if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) { - mContext.setTaskbarWindowFullscreen(true); - mSlideInView.show(); + PredictionRowView predictionRowView = + mAppsView.getFloatingHeaderView().findFixedRowByType(PredictionRowView.class); + predictionRowView.setPredictedApps(predictedApps); } } + + /** Opens the {@link TaskbarAllAppsContainerView}. */ + public void show() { + if (!FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) { + return; + } + + mAppsView.getFloatingHeaderView().findFixedRowByType(AppsDividerView.class) + .setShowAllAppsLabel( + !mContext.getOnboardingPrefs().hasReachedMaxCount(ALL_APPS_VISITED_COUNT)); + mContext.getOnboardingPrefs().incrementEventCount(ALL_APPS_VISITED_COUNT); + mContext.setTaskbarWindowFullscreen(true); + mSlideInView.show(); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java index 2bafccdb62..2e18a40b68 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java @@ -52,8 +52,6 @@ public class TaskbarModelCallbacks implements // Initialized in init. private TaskbarControllers mControllers; - private boolean mBindInProgress = false; - public TaskbarModelCallbacks( TaskbarActivityContext context, TaskbarView container) { mContext = context; @@ -66,14 +64,14 @@ public class TaskbarModelCallbacks implements @Override public void startBinding() { - mBindInProgress = true; + mContext.setBindingItems(true); mHotseatItems.clear(); mPredictedItems = Collections.emptyList(); } @Override public void finishBindingItems(IntSet pagesBoundFirst) { - mBindInProgress = false; + mContext.setBindingItems(false); commitItemsToUI(); } @@ -159,11 +157,13 @@ public class TaskbarModelCallbacks implements if (item.containerId == Favorites.CONTAINER_HOTSEAT_PREDICTION) { mPredictedItems = item.items; commitItemsToUI(); + } else if (item.containerId == Favorites.CONTAINER_PREDICTION) { + mControllers.taskbarAllAppsViewController.setPredictedApps(item.items); } } private void commitItemsToUI() { - if (mBindInProgress) { + if (mContext.isBindingItems()) { return; } @@ -212,6 +212,5 @@ public class TaskbarModelCallbacks implements pw.println( String.format("%s\tpredicted items count=%s", prefix, mPredictedItems.size())); } - pw.println(String.format("%s\tmBindInProgress=%b", prefix, mBindInProgress)); } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 9050ddc511..1073d766f1 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -69,7 +69,6 @@ import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchControlle import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController; import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController; import com.android.launcher3.util.ItemInfoMatcher; -import com.android.launcher3.util.OnboardingPrefs; import com.android.launcher3.util.PendingRequestArgs; import com.android.launcher3.util.TouchController; import com.android.launcher3.util.UiThreadHelper; @@ -162,7 +161,7 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { } @Override - protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) { + protected QuickstepOnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) { return new QuickstepOnboardingPrefs(this, sharedPrefs); } @@ -235,8 +234,10 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { public void bindExtraContainerItems(FixedContainerItems item) { if (item.containerId == Favorites.CONTAINER_PREDICTION) { mAllAppsPredictions = item; - getAppsView().getFloatingHeaderView().findFixedRowByType(PredictionRowView.class) - .setPredictedApps(item.items); + PredictionRowView predictionRowView = + getAppsView().getFloatingHeaderView().findFixedRowByType( + PredictionRowView.class); + predictionRowView.setPredictedApps(item.items); } else if (item.containerId == Favorites.CONTAINER_HOTSEAT_PREDICTION) { mHotseatPredictionController.setPredictedItems(item); } else if (item.containerId == Favorites.CONTAINER_WIDGETS_PREDICTION) { diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java index 6d6e802231..54642a2071 100644 --- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java +++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java @@ -28,6 +28,7 @@ import android.content.SharedPreferences; import com.android.launcher3.LauncherState; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; +import com.android.launcher3.appprediction.AppsDividerView; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.statemanager.StateManager; @@ -132,5 +133,24 @@ public class QuickstepOnboardingPrefs extends OnboardingPrefs } }); } + + if (!hasReachedMaxCount(ALL_APPS_VISITED_COUNT)) { + mLauncher.getStateManager().addStateListener(new StateListener() { + @Override + public void onStateTransitionComplete(LauncherState finalState) { + if (finalState == ALL_APPS) { + incrementEventCount(ALL_APPS_VISITED_COUNT); + return; + } + + boolean hasReachedMaxCount = hasReachedMaxCount(ALL_APPS_VISITED_COUNT); + mLauncher.getAppsView().getFloatingHeaderView().findFixedRowByType( + AppsDividerView.class).setShowAllAppsLabel(!hasReachedMaxCount); + if (hasReachedMaxCount) { + mLauncher.getStateManager().removeStateListener(this); + } + } + }); + } } } diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java index ec96c6de5d..42f70536d4 100644 --- a/src/com/android/launcher3/BaseActivity.java +++ b/src/com/android/launcher3/BaseActivity.java @@ -34,6 +34,7 @@ import android.util.Log; import androidx.annotation.IntDef; +import com.android.launcher3.DeviceProfile.DeviceProfileListenable; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.util.SystemUiController; @@ -44,11 +45,13 @@ import com.android.launcher3.views.ScrimView; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.util.ArrayList; +import java.util.List; /** * Launcher BaseActivity */ -public abstract class BaseActivity extends Activity implements ActivityContext { +public abstract class BaseActivity extends Activity implements ActivityContext, + DeviceProfileListenable { private static final String TAG = "BaseActivity"; @@ -142,6 +145,11 @@ public abstract class BaseActivity extends Activity implements ActivityContext { return mDeviceProfile; } + @Override + public List getOnDeviceProfileChangeListeners() { + return mDPChangeListeners; + } + /** * Returns {@link StatsLogManager} for user event logging. */ @@ -261,20 +269,6 @@ public abstract class BaseActivity extends Activity implements ActivityContext { protected void onActivityFlagsChanged(int changeBits) { } - public void addOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) { - mDPChangeListeners.add(listener); - } - - public void removeOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) { - mDPChangeListeners.remove(listener); - } - - protected void dispatchDeviceProfileChanged() { - for (int i = mDPChangeListeners.size() - 1; i >= 0; i--) { - mDPChangeListeners.get(i).onDeviceProfileChanged(mDeviceProfile); - } - } - public void addMultiWindowModeChangedListener(MultiWindowModeChangedListener listener) { mMultiWindowModeChangedListeners.add(listener); } diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index c456a4d00a..62703ad2e0 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -44,6 +44,7 @@ import com.android.launcher3.util.DisplayController.Info; import com.android.launcher3.util.WindowBounds; import java.io.PrintWriter; +import java.util.List; @SuppressLint("NewApi") public class DeviceProfile { @@ -1223,6 +1224,35 @@ public class DeviceProfile { void onDeviceProfileChanged(DeviceProfile dp); } + /** Allows registering listeners for {@link DeviceProfile} changes. */ + public interface DeviceProfileListenable { + + /** The current device profile. */ + DeviceProfile getDeviceProfile(); + + /** Registered {@link OnDeviceProfileChangeListener} instances. */ + List getOnDeviceProfileChangeListeners(); + + /** Notifies listeners of a {@link DeviceProfile} change. */ + default void dispatchDeviceProfileChanged() { + DeviceProfile deviceProfile = getDeviceProfile(); + List listeners = getOnDeviceProfileChangeListeners(); + for (int i = listeners.size() - 1; i >= 0; i--) { + listeners.get(i).onDeviceProfileChanged(deviceProfile); + } + } + + /** Register listener for {@link DeviceProfile} changes. */ + default void addOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) { + getOnDeviceProfileChangeListeners().add(listener); + } + + /** Unregister listener for {@link DeviceProfile} changes. */ + default void removeOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) { + getOnDeviceProfileChangeListeners().remove(listener); + } + } + public static class Builder { private Context mContext; private InvariantDeviceProfile mInv; diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index ebc0c75fe6..fcd147ffdf 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -351,7 +351,7 @@ public class Launcher extends StatefulActivity implements Launche // We only want to get the SharedPreferences once since it does an FS stat each time we get // it from the context. private SharedPreferences mSharedPrefs; - private OnboardingPrefs mOnboardingPrefs; + private OnboardingPrefs mOnboardingPrefs; // Activity result which needs to be processed after workspace has loaded. private ActivityResultInfo mPendingActivityResult; @@ -557,11 +557,12 @@ public class Launcher extends StatefulActivity implements Launche return new LauncherOverlayManager() { }; } - protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) { + protected OnboardingPrefs createOnboardingPrefs( + SharedPreferences sharedPrefs) { return new OnboardingPrefs<>(this, sharedPrefs); } - public OnboardingPrefs getOnboardingPrefs() { + public OnboardingPrefs getOnboardingPrefs() { return mOnboardingPrefs; } @@ -588,7 +589,7 @@ public class Launcher extends StatefulActivity implements Launche } @Override - protected void dispatchDeviceProfileChanged() { + public void dispatchDeviceProfileChanged() { super.dispatchDeviceProfileChanged(); mOverlayManager.onDeviceProvideChanged(); } @@ -1782,6 +1783,11 @@ public class Launcher extends StatefulActivity implements Launche return mWorkspaceLoading; } + @Override + public boolean isBindingItems() { + return mWorkspaceLoading; + } + private void setWorkspaceLoading(boolean value) { mWorkspaceLoading = value; } diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java index fb87f8843e..114f8130c7 100644 --- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java @@ -62,7 +62,6 @@ public class ActivityAllAppsContainerView extend public ActivityAllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - mActivityContext.addOnDeviceProfileChangeListener(this); } public SearchUiManager getSearchUiManager() { diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java index a66ae78c12..59e21c099c 100644 --- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java @@ -48,6 +48,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.DeviceProfile.DeviceProfileListenable; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget.DragObject; @@ -75,9 +76,10 @@ import java.util.List; * * @param Type of context inflating all apps. */ -public abstract class BaseAllAppsContainerView extends - SpringRelativeLayout implements DragSource, Insettable, OnDeviceProfileChangeListener, - OnActivePageChangedListener, ScrimView.ScrimDrawingController { +public abstract class BaseAllAppsContainerView extends SpringRelativeLayout implements DragSource, Insettable, + OnDeviceProfileChangeListener, OnActivePageChangedListener, + ScrimView.ScrimDrawingController { private static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page"; @@ -148,6 +150,7 @@ public abstract class BaseAllAppsContainerView void setup( - List.AdapterHolder> mAH, boolean tabsHidden) { + void setup(AllAppsRecyclerView mainRV, AllAppsRecyclerView workRV, boolean tabsHidden) { for (FloatingHeaderRow row : mAllRows) { row.setup(this, mAllRows, tabsHidden); } @@ -235,10 +233,8 @@ public class FloatingHeaderView extends LinearLayout implements mTabsHidden = tabsHidden; mTabLayout.setVisibility(tabsHidden ? View.GONE : View.VISIBLE); - mMainRV = setupRV(mMainRV, - mAH.get(BaseAllAppsContainerView.AdapterHolder.MAIN).mRecyclerView); - mWorkRV = setupRV(mWorkRV, - mAH.get(BaseAllAppsContainerView.AdapterHolder.WORK).mRecyclerView); + mMainRV = setupRV(mMainRV, mainRV); + mWorkRV = setupRV(mWorkRV, workRV); mParent = (ViewGroup) mMainRV.getParent(); setMainActive(mMainRVActive || mWorkRV == null); reset(false); diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java index 5ba0d30256..39d7cfe8d2 100644 --- a/src/com/android/launcher3/util/OnboardingPrefs.java +++ b/src/com/android/launcher3/util/OnboardingPrefs.java @@ -20,7 +20,7 @@ import android.util.ArrayMap; import androidx.annotation.StringDef; -import com.android.launcher3.Launcher; +import com.android.launcher3.views.ActivityContext; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -29,8 +29,10 @@ import java.util.Map; /** * Stores and retrieves onboarding-related data via SharedPreferences. + * + * @param Context which owns these preferences. */ -public class OnboardingPrefs { +public class OnboardingPrefs { public static final String HOME_BOUNCE_SEEN = "launcher.apps_view_shown"; public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count"; @@ -39,13 +41,15 @@ public class OnboardingPrefs { public static final String SEARCH_EDU_SEEN = "launcher.search_edu_seen"; public static final String SEARCH_SNACKBAR_COUNT = "launcher.keyboard_snackbar_count"; public static final String TASKBAR_EDU_SEEN = "launcher.taskbar_edu_seen"; + public static final String ALL_APPS_VISITED_COUNT = "launcher.all_apps_visited_count"; // When adding a new key, add it here as well, to be able to reset it from Developer Options. public static final Map ALL_PREF_KEYS = Map.of( "All Apps Bounce", new String[] { HOME_BOUNCE_SEEN, HOME_BOUNCE_COUNT }, "Hybrid Hotseat Education", new String[] { HOTSEAT_DISCOVERY_TIP_COUNT, HOTSEAT_LONGPRESS_TIP_SEEN }, "Search Education", new String[] { SEARCH_EDU_SEEN, SEARCH_SNACKBAR_COUNT }, - "Taskbar Education", new String[] { TASKBAR_EDU_SEEN } + "Taskbar Education", new String[] { TASKBAR_EDU_SEEN }, + "All Apps Visited Count", new String[] {ALL_APPS_VISITED_COUNT} ); /** @@ -67,7 +71,8 @@ public class OnboardingPrefs { @StringDef(value = { HOME_BOUNCE_COUNT, HOTSEAT_DISCOVERY_TIP_COUNT, - SEARCH_SNACKBAR_COUNT + SEARCH_SNACKBAR_COUNT, + ALL_APPS_VISITED_COUNT }) @Retention(RetentionPolicy.SOURCE) public @interface EventCountKey { @@ -80,6 +85,7 @@ public class OnboardingPrefs { maxCounts.put(HOME_BOUNCE_COUNT, 3); maxCounts.put(HOTSEAT_DISCOVERY_TIP_COUNT, 5); maxCounts.put(SEARCH_SNACKBAR_COUNT, 3); + maxCounts.put(ALL_APPS_VISITED_COUNT, 20); MAX_COUNTS = Collections.unmodifiableMap(maxCounts); } diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java index a318363af3..3c90eea5d1 100644 --- a/src/com/android/launcher3/views/ActivityContext.java +++ b/src/com/android/launcher3/views/ActivityContext.java @@ -34,6 +34,7 @@ import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.StringCache; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.popup.PopupDataProvider; +import com.android.launcher3.util.OnboardingPrefs; import com.android.launcher3.util.ViewCache; /** @@ -138,6 +139,16 @@ public interface ActivityContext { */ default void applyOverwritesToLogItem(LauncherAtom.ItemInfo.Builder itemInfoBuilder) { } + /** Onboarding preferences for any onboarding data within this context. */ + default OnboardingPrefs getOnboardingPrefs() { + return null; + } + + /** Returns {@code true} if items are currently being bound within this context. */ + default boolean isBindingItems() { + return false; + } + /** * Returns the ActivityContext associated with the given Context, or throws an exception if * the Context is not associated with any ActivityContext.