Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 099945b0 authored by Brian Isganitis's avatar Brian Isganitis
Browse files

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
parent 8c3cb4e3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@
            android:paddingTop="@dimen/all_apps_header_top_padding"
            android:orientation="vertical">

            <include layout="@layout/floating_header_content" />

            <include layout="@layout/all_apps_personal_work_tabs" />
        </com.android.launcher3.allapps.FloatingHeaderView>

+14 −56
Original line number Diff line number Diff line
@@ -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<LauncherState>,
        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<LauncherState
        ALL_APPS_LABEL
    }

    private final Launcher mLauncher;
    private final TextPaint mPaint = new TextPaint();
    private DividerType mDividerType = DividerType.NONE;

@@ -86,7 +79,6 @@ public class AppsDividerView extends View implements StateListener<LauncherState

    public AppsDividerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mLauncher = Launcher.getLauncher(context);

        boolean isMainColorDark = Themes.getAttrBoolean(context, R.attr.isMainColorDark);
        mDividerSize = new int[]{
@@ -101,6 +93,9 @@ public class AppsDividerView extends View implements StateListener<LauncherState
        mAllAppsLabelTextColor = ContextCompat.getColor(context, isMainColorDark
                ? R.color.all_apps_label_text_dark
                : R.color.all_apps_label_text);

        mShowAllAppsLabel = !ActivityContext.lookupContext(
                getContext()).getOnboardingPrefs().hasReachedMaxCount(ALL_APPS_VISITED_COUNT);
    }

    public void setup(FloatingHeaderView parent, FloatingHeaderRow[] rows, boolean tabsHidden) {
@@ -110,6 +105,14 @@ public class AppsDividerView extends View implements StateListener<LauncherState
        updateDividerType();
    }

    /** {@code true} if all apps label should be shown in place of divider. */
    public void setShowAllAppsLabel(boolean showAllAppsLabel) {
        if (showAllAppsLabel != mShowAllAppsLabel) {
            mShowAllAppsLabel = showAllAppsLabel;
            updateDividerType();
        }
    }

    @Override
    public int getExpectedHeight() {
        return getPaddingTop() + getPaddingBottom();
@@ -235,51 +238,6 @@ public class AppsDividerView extends View implements StateListener<LauncherState
                getPaddingBottom() + getPaddingTop());
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();

        if (shouldShowAllAppsLabel()) {
            mShowAllAppsLabel = true;
            mLauncher.getStateManager().addStateListener(this);
            updateDividerType();
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mLauncher.getStateManager().removeStateListener(this);
    }

    @Override
    public void onStateTransitionComplete(LauncherState finalState) {
        if (finalState == ALL_APPS) {
            setAllAppsVisitedCount(getAllAppsVisitedCount() + 1);
        } else {
            if (mShowAllAppsLabel != shouldShowAllAppsLabel()) {
                mShowAllAppsLabel = !mShowAllAppsLabel;
                updateDividerType();
            }

            if (!mShowAllAppsLabel) {
                mLauncher.getStateManager().removeStateListener(this);
            }
        }
    }

    private void setAllAppsVisitedCount(int count) {
        mLauncher.getSharedPrefs().edit().putInt(ALL_APPS_VISITED_COUNT, count).apply();
    }

    private int getAllAppsVisitedCount() {
        return mLauncher.getSharedPrefs().getInt(ALL_APPS_VISITED_COUNT, 0);
    }

    private boolean shouldShowAllAppsLabel() {
        return getAllAppsVisitedCount() < SHOW_ALL_APPS_LABEL_ON_ALL_APPS_VISITED_COUNT;
    }

    @Override
    public void setInsets(Rect insets, DeviceProfile grid) {
        int leftRightPadding = grid.allAppsLeftRightPadding;
+32 −27
Original line number Diff line number Diff line
@@ -31,8 +31,8 @@ import androidx.annotation.Nullable;

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.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.allapps.FloatingHeaderRow;
import com.android.launcher3.allapps.FloatingHeaderView;
@@ -43,18 +43,18 @@ import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorH
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.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.views.ActivityContext;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@TargetApi(Build.VERSION_CODES.P)
public class PredictionRowView extends LinearLayout implements
        OnDeviceProfileChangeListener, FloatingHeaderRow {
public class PredictionRowView<T extends Context & ActivityContext & DeviceProfileListenable>
        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<WorkspaceItemInfo> mPredictedApps = new ArrayList<>();

    private FloatingHeaderView mParent;
    private boolean mScrolledOut;

    private boolean mPredictionsEnabled = false;

    @Nullable
    private List<ItemInfo> mPendingPredictedItems;
    private @Nullable List<ItemInfo> 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<ItemInfo> 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);
+34 −1
Original line number Diff line number Diff line
@@ -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<OnDeviceProfileChangeListener> 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<TaskbarActivityContext> 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<OnDeviceProfileChangeListener> 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<TaskbarActivityContext> 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);
    }
}
+28 −3
Original line number Diff line number Diff line
@@ -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 {
        }
    }

    /** Binds the current app predictions to all apps {@link PredictionRowView}. */
    public void setPredictedApps(List<ItemInfo> predictedApps) {
        if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) {
            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()) {
        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();
    }
}
}
Loading