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 78e39bb268..fe091efecd 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; @@ -124,14 +132,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); mImeDrawsImeNavBar = SysUINavigationMode.getImeDrawsImeNavBar(windowContext); @@ -229,6 +240,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ public void updateDeviceProfile(DeviceProfile dp) { mDeviceProfile = dp; updateIconSize(getResources()); + dispatchDeviceProfileChanged(); } private void updateIconSize(Resources resources) { @@ -304,6 +316,11 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ return mDeviceProfile; } + @Override + public List getOnDeviceProfileChangeListeners() { + return mDPChangeListeners; + } + @Override public Rect getFolderBoundingBox() { return mControllers.taskbarDragLayerController.getFolderBoundingBox(); @@ -394,6 +411,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 */ @@ -738,6 +769,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.