Merge "Implementation of PredictionRowView. > Enable to use floating for prediction row even without tabs. > Behind ALL_APPS_PREDICTION_ROW_VIEW feature flag. > Expand/Collapse personal/work tabs in stopped intermediate state." into ub-launcher3-master
This commit is contained in:
committed by
Android (Google) Code Review
commit
86a8fde10b
+10
-5
@@ -35,21 +35,27 @@
|
||||
android:id="@+id/all_apps_header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="true"
|
||||
android:paddingTop="30dp"
|
||||
android:paddingTop="@dimen/all_apps_header_top_padding"
|
||||
android:clipToPadding="false"
|
||||
android:layout_below="@id/search_container_all_apps" >
|
||||
|
||||
<com.android.launcher3.allapps.PredictionRowView
|
||||
android:id="@+id/header_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<include layout="@layout/all_apps_divider"
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@+id/tabs" />
|
||||
|
||||
<com.android.launcher3.views.SlidingTabStrip
|
||||
android:id="@+id/tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/all_apps_header_tab_height"
|
||||
android:layout_below="@id/header_content"
|
||||
android:orientation="horizontal">
|
||||
android:orientation="horizontal" >
|
||||
<Button
|
||||
android:id="@+id/tab_personal"
|
||||
android:layout_width="0dp"
|
||||
@@ -67,7 +73,6 @@
|
||||
android:textColor="@color/all_apps_tab_text"
|
||||
android:background="?android:attr/selectableItemBackground"/>
|
||||
</com.android.launcher3.views.SlidingTabStrip>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<!-- Note: we are reusing/repurposing a system attribute for search layout, because of a
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:descendantFocusability="afterDescendants"
|
||||
android:paddingTop="30dp">
|
||||
android:paddingTop="@dimen/all_apps_header_top_padding">
|
||||
|
||||
<include layout="@layout/all_apps_rv_layout" />
|
||||
|
||||
|
||||
@@ -92,6 +92,8 @@
|
||||
<dimen name="all_apps_caret_workspace_offset">18dp</dimen>
|
||||
<dimen name="all_apps_header_tab_height">50dp</dimen>
|
||||
<dimen name="all_apps_tabs_indicator_height">2dp</dimen>
|
||||
<dimen name="all_apps_header_top_padding">36dp</dimen>
|
||||
<dimen name="all_apps_prediction_row_divider_height">17dp</dimen>
|
||||
|
||||
<!-- Search bar in All Apps -->
|
||||
<dimen name="all_apps_header_max_elevation">3dp</dimen>
|
||||
|
||||
@@ -281,6 +281,9 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,
|
||||
mAH[i].recyclerView.scrollToTop();
|
||||
}
|
||||
}
|
||||
if (mFloatingHeaderHandler != null) {
|
||||
mFloatingHeaderHandler.reset();
|
||||
}
|
||||
// Reset the search bar and base recycler view after transitioning home
|
||||
mSearchUiManager.reset();
|
||||
}
|
||||
@@ -301,6 +304,7 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,
|
||||
});
|
||||
|
||||
mHeader = findViewById(R.id.all_apps_header);
|
||||
mFloatingHeaderHandler = new FloatingHeaderHandler(mHeader);
|
||||
rebindAdapters(mUsingTabs);
|
||||
|
||||
mSearchContainer = findViewById(R.id.search_container_all_apps);
|
||||
@@ -431,10 +435,14 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,
|
||||
mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
|
||||
setupWorkProfileTabs();
|
||||
setupHeader();
|
||||
mHeader.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mHeader.setVisibility(View.GONE);
|
||||
mAH[AdapterHolder.MAIN].setup(findViewById(R.id.apps_list_view), null);
|
||||
if (FeatureFlags.ALL_APPS_PREDICTION_ROW_VIEW) {
|
||||
setupHeader();
|
||||
} else {
|
||||
mFloatingHeaderHandler = null;
|
||||
mHeader.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
applyTouchDelegate();
|
||||
@@ -512,7 +520,7 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,
|
||||
}
|
||||
|
||||
public void setPredictedApps(List<ComponentKeyMapper<AppInfo>> apps) {
|
||||
if (mUsingTabs) {
|
||||
if (mFloatingHeaderHandler != null) {
|
||||
mFloatingHeaderHandler.getContentView().setPredictedApps(apps);
|
||||
}
|
||||
mAH[AdapterHolder.MAIN].appsList.setPredictedApps(apps);
|
||||
@@ -535,15 +543,24 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,
|
||||
}
|
||||
|
||||
private void setupHeader() {
|
||||
mHeader.setVisibility(View.VISIBLE);
|
||||
int contentHeight = mLauncher.getDeviceProfile().allAppsCellHeightPx;
|
||||
if (!mUsingTabs) {
|
||||
contentHeight += getResources()
|
||||
.getDimensionPixelSize(R.dimen.all_apps_prediction_row_divider_height);
|
||||
}
|
||||
RecyclerView mainRV = mAH[AdapterHolder.MAIN].recyclerView;
|
||||
RecyclerView workRV = mAH[AdapterHolder.WORK] != null
|
||||
? mAH[AdapterHolder.WORK].recyclerView : null;
|
||||
mFloatingHeaderHandler = new FloatingHeaderHandler(mHeader, mainRV, workRV, contentHeight);
|
||||
mFloatingHeaderHandler.getContentView().setNumAppsPerRow(mNumPredictedAppsPerRow);
|
||||
mFloatingHeaderHandler.getContentView().setComponentToAppMap(mComponentToAppMap);
|
||||
RecyclerView workRV = mAH[AdapterHolder.WORK].recyclerView;
|
||||
mFloatingHeaderHandler.setup(mainRV, workRV, contentHeight);
|
||||
mFloatingHeaderHandler.getContentView().setup(mAH[AdapterHolder.MAIN].adapter,
|
||||
mComponentToAppMap, mNumPredictedAppsPerRow);
|
||||
|
||||
int padding = contentHeight;
|
||||
if (!mUsingTabs) {
|
||||
padding += mHeader.getPaddingTop() + mHeader.getPaddingBottom();
|
||||
}
|
||||
for (int i = 0; i < mAH.length; i++) {
|
||||
mAH[i].paddingTopForTabs = contentHeight;
|
||||
mAH[i].paddingTopForTabs = padding;
|
||||
mAH[i].applyPadding();
|
||||
}
|
||||
}
|
||||
@@ -556,7 +573,9 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,
|
||||
|
||||
public void onSearchResultsChanged() {
|
||||
for (int i = 0; i < mAH.length; i++) {
|
||||
mAH[i].recyclerView.onSearchResultsChanged();
|
||||
if (mAH[i].recyclerView != null) {
|
||||
mAH[i].recyclerView.onSearchResultsChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,9 +659,14 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,
|
||||
|
||||
void applyPadding() {
|
||||
if (recyclerView != null) {
|
||||
int paddingTop = mUsingTabs ? paddingTopForTabs : padding.top;
|
||||
int paddingTop = mUsingTabs || FeatureFlags.ALL_APPS_PREDICTION_ROW_VIEW
|
||||
? paddingTopForTabs : padding.top;
|
||||
recyclerView.setPadding(padding.left, paddingTop, padding.right, padding.bottom);
|
||||
}
|
||||
if (mFloatingHeaderHandler != null) {
|
||||
mFloatingHeaderHandler.getContentView()
|
||||
.setPadding(padding.left, 0 , padding.right, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void applyNumsPerRow() {
|
||||
@@ -652,7 +676,7 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,
|
||||
}
|
||||
adapter.setNumAppsPerRow(mNumAppsPerRow);
|
||||
appsList.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow);
|
||||
if (mUsingTabs && mFloatingHeaderHandler != null) {
|
||||
if (mFloatingHeaderHandler != null) {
|
||||
mFloatingHeaderHandler.getContentView()
|
||||
.setNumAppsPerRow(mNumPredictedAppsPerRow);
|
||||
}
|
||||
|
||||
@@ -460,7 +460,7 @@ public class AlphabeticalAppsList {
|
||||
mFastScrollerSections.clear();
|
||||
mAdapterItems.clear();
|
||||
|
||||
if (!FeatureFlags.ALL_APPS_TABS_ENABLED) {
|
||||
if (!FeatureFlags.ALL_APPS_PREDICTION_ROW_VIEW) {
|
||||
if (DEBUG_PREDICTIONS) {
|
||||
if (mPredictedAppComponents.isEmpty() && !mApps.isEmpty()) {
|
||||
mPredictedAppComponents.add(new ComponentKeyMapper<AppInfo>(new ComponentKey(mApps.get(0).componentName,
|
||||
|
||||
@@ -15,36 +15,52 @@
|
||||
*/
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Rect;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
|
||||
public class FloatingHeaderHandler extends RecyclerView.OnScrollListener {
|
||||
public class FloatingHeaderHandler extends RecyclerView.OnScrollListener
|
||||
implements ValueAnimator.AnimatorUpdateListener {
|
||||
|
||||
private final int mMaxTranslation;
|
||||
private final View mHeaderView;
|
||||
private final PredictionRowView mContentView;
|
||||
private final RecyclerView mMainRV;
|
||||
private final RecyclerView mWorkRV;
|
||||
private final PredictionRowView mPredictionRow;
|
||||
private final ViewGroup mTabLayout;
|
||||
private final View mDivider;
|
||||
private final Rect mClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
|
||||
|
||||
private RecyclerView mMainRV;
|
||||
private RecyclerView mWorkRV;
|
||||
private boolean mTopOnlyMode;
|
||||
private boolean mHeaderHidden;
|
||||
private int mMaxTranslation;
|
||||
private int mSnappedScrolledY;
|
||||
private int mTranslationY;
|
||||
private int mMainScrolledY;
|
||||
private int mWorkScrolledY;
|
||||
private boolean mMainRVActive;
|
||||
|
||||
public FloatingHeaderHandler(@NonNull View header, @NonNull RecyclerView personalRV,
|
||||
@Nullable RecyclerView workRV, int contentHeight) {
|
||||
public FloatingHeaderHandler(@NonNull ViewGroup header) {
|
||||
mHeaderView = header;
|
||||
mContentView = mHeaderView.findViewById(R.id.header_content);
|
||||
mContentView.getLayoutParams().height = contentHeight;
|
||||
mMaxTranslation = contentHeight;
|
||||
mTabLayout = header.findViewById(R.id.tabs);
|
||||
mDivider = header.findViewById(R.id.divider);
|
||||
mPredictionRow = header.findViewById(R.id.header_content);
|
||||
}
|
||||
|
||||
public void setup(@NonNull RecyclerView personalRV, @Nullable RecyclerView workRV,
|
||||
int predictionRowHeight) {
|
||||
mTopOnlyMode = workRV == null;
|
||||
mTabLayout.setVisibility(mTopOnlyMode ? View.GONE : View.VISIBLE);
|
||||
mPredictionRow.getLayoutParams().height = predictionRowHeight;
|
||||
mMaxTranslation = predictionRowHeight;
|
||||
mMainRV = personalRV;
|
||||
mMainRV.addOnScrollListener(this);
|
||||
mWorkRV = workRV;
|
||||
@@ -52,6 +68,18 @@ public class FloatingHeaderHandler extends RecyclerView.OnScrollListener {
|
||||
workRV.addOnScrollListener(this);
|
||||
}
|
||||
setMainActive(true);
|
||||
setupDivider();
|
||||
}
|
||||
|
||||
private void setupDivider() {
|
||||
Resources res = mHeaderView.getResources();
|
||||
int verticalGap = res.getDimensionPixelSize(R.dimen.all_apps_divider_margin_vertical);
|
||||
int sideGap = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
|
||||
mDivider.setPadding(sideGap, verticalGap,sideGap, mTopOnlyMode ? verticalGap : 0);
|
||||
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mDivider.getLayoutParams();
|
||||
lp.removeRule(RelativeLayout.ALIGN_BOTTOM);
|
||||
lp.addRule(RelativeLayout.ALIGN_BOTTOM, mTopOnlyMode ? R.id.header_content : R.id.tabs);
|
||||
mDivider.setLayoutParams(lp);
|
||||
}
|
||||
|
||||
public void setMainActive(boolean active) {
|
||||
@@ -65,7 +93,15 @@ public class FloatingHeaderHandler extends RecyclerView.OnScrollListener {
|
||||
}
|
||||
|
||||
public PredictionRowView getContentView() {
|
||||
return mContentView;
|
||||
return mPredictionRow;
|
||||
}
|
||||
|
||||
public ViewGroup getTabLayout() {
|
||||
return mTabLayout;
|
||||
}
|
||||
|
||||
public View getDivider() {
|
||||
return mDivider;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,27 +111,39 @@ public class FloatingHeaderHandler extends RecyclerView.OnScrollListener {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mAnimator.isStarted()) {
|
||||
mAnimator.cancel();
|
||||
}
|
||||
|
||||
int current = isMainRV
|
||||
? (mMainScrolledY -= dy)
|
||||
: (mWorkScrolledY -= dy);
|
||||
|
||||
if (dy == 0) {
|
||||
setExpanded(true);
|
||||
} else {
|
||||
moved(current);
|
||||
apply();
|
||||
}
|
||||
moved(current);
|
||||
apply();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
mMainScrolledY = 0;
|
||||
mWorkScrolledY = 0;
|
||||
setExpanded(true);
|
||||
}
|
||||
|
||||
private boolean canSnapAt(int currentScrollY) {
|
||||
return !mTopOnlyMode || Math.abs(currentScrollY) <= mPredictionRow.getHeight();
|
||||
}
|
||||
|
||||
private void moved(final int currentScrollY) {
|
||||
if (mHeaderHidden) {
|
||||
if (currentScrollY <= mSnappedScrolledY) {
|
||||
mSnappedScrolledY = currentScrollY;
|
||||
if (canSnapAt(currentScrollY)) {
|
||||
mSnappedScrolledY = currentScrollY;
|
||||
}
|
||||
} else {
|
||||
mHeaderHidden = false;
|
||||
}
|
||||
mTranslationY = currentScrollY;
|
||||
} else {
|
||||
} else if (!mHeaderHidden) {
|
||||
mTranslationY = currentScrollY - mSnappedScrolledY - mMaxTranslation;
|
||||
|
||||
// update state vars
|
||||
@@ -110,20 +158,36 @@ public class FloatingHeaderHandler extends RecyclerView.OnScrollListener {
|
||||
}
|
||||
|
||||
private void apply() {
|
||||
int uncappedTranslationY = mTranslationY;
|
||||
mTranslationY = Math.max(mTranslationY, -mMaxTranslation);
|
||||
mHeaderView.setTranslationY(mTranslationY);
|
||||
mPredictionRow.setTranslationY(uncappedTranslationY);
|
||||
mTabLayout.setTranslationY(mTranslationY);
|
||||
mDivider.setTranslationY(mTopOnlyMode ? uncappedTranslationY : mTranslationY);
|
||||
mClip.top = mMaxTranslation + mTranslationY;
|
||||
// clipping on a draw might cause additional redraw
|
||||
mMainRV.setClipBounds(mClip);
|
||||
if (mWorkRV != null) {
|
||||
mWorkRV.setClipBounds(mClip);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
|
||||
if (!mTopOnlyMode && newState == RecyclerView.SCROLL_STATE_IDLE
|
||||
&& mTranslationY != -mMaxTranslation && mTranslationY != 0) {
|
||||
float scroll = Math.abs(getCurrentScroll());
|
||||
boolean expand = scroll > mMaxTranslation
|
||||
? Math.abs(mTranslationY) < mMaxTranslation / 2 : true;
|
||||
setExpanded(expand);
|
||||
}
|
||||
}
|
||||
|
||||
private void setExpanded(boolean expand) {
|
||||
int translateTo = expand ? 0 : -mMaxTranslation;
|
||||
mTranslationY = translateTo;
|
||||
apply();
|
||||
|
||||
mAnimator.setIntValues(mTranslationY, translateTo);
|
||||
mAnimator.addUpdateListener(this);
|
||||
mAnimator.setDuration(150);
|
||||
mAnimator.start();
|
||||
mHeaderHidden = !expand;
|
||||
mSnappedScrolledY = expand ? getCurrentScroll() - mMaxTranslation : getCurrentScroll();
|
||||
}
|
||||
@@ -136,4 +200,10 @@ public class FloatingHeaderHandler extends RecyclerView.OnScrollListener {
|
||||
return mMainRVActive ? mMainScrolledY : mWorkScrolledY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
mTranslationY = (Integer) animation.getAnimatedValue();
|
||||
apply();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,9 +21,11 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.launcher3.AppInfo;
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.ComponentKeyMapper;
|
||||
@@ -43,6 +45,8 @@ public class PredictionRowView extends LinearLayout {
|
||||
private final List<ComponentKeyMapper<AppInfo>> mPredictedAppComponents = new ArrayList<>();
|
||||
// The set of predicted apps resolved from the component names and the current set of apps
|
||||
private final List<AppInfo> mPredictedApps = new ArrayList<>();
|
||||
// This adapter is only used to create an identical item w/ same behavior as in the all apps RV
|
||||
private AllAppsGridAdapter mAdapter;
|
||||
|
||||
public PredictionRowView(@NonNull Context context) {
|
||||
this(context, null);
|
||||
@@ -53,8 +57,11 @@ public class PredictionRowView extends LinearLayout {
|
||||
setOrientation(LinearLayout.HORIZONTAL);
|
||||
}
|
||||
|
||||
public void setComponentToAppMap(HashMap<ComponentKey, AppInfo> componentToAppMap) {
|
||||
this.mComponentToAppMap = componentToAppMap;
|
||||
public void setup(AllAppsGridAdapter adapter,
|
||||
HashMap<ComponentKey, AppInfo> componentToAppMap, int numPredictedAppsPerRow) {
|
||||
mAdapter = adapter;
|
||||
mComponentToAppMap = componentToAppMap;
|
||||
mNumPredictedAppsPerRow = numPredictedAppsPerRow;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,10 +71,6 @@ public class PredictionRowView extends LinearLayout {
|
||||
mNumPredictedAppsPerRow = numPredictedAppsPerRow;
|
||||
}
|
||||
|
||||
public void onAppsUpdated() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the predicted apps.
|
||||
*/
|
||||
@@ -87,15 +90,35 @@ public class PredictionRowView extends LinearLayout {
|
||||
public void setPredictedApps(List<ComponentKeyMapper<AppInfo>> apps) {
|
||||
mPredictedAppComponents.clear();
|
||||
mPredictedAppComponents.addAll(apps);
|
||||
mPredictedApps.addAll(processPredictedAppComponents(mPredictedAppComponents));
|
||||
onAppsUpdated();
|
||||
}
|
||||
|
||||
List<AppInfo> newPredictedApps = processPredictedAppComponents(apps);
|
||||
// We only need to do work if any of the visible predicted apps have changed.
|
||||
if (!newPredictedApps.equals(mPredictedApps)) {
|
||||
if (newPredictedApps.size() == mPredictedApps.size()) {
|
||||
swapInNewPredictedApps(newPredictedApps);
|
||||
private void onAppsUpdated() {
|
||||
if (getChildCount() != mNumPredictedAppsPerRow) {
|
||||
while (getChildCount() > mNumPredictedAppsPerRow) {
|
||||
removeViewAt(0);
|
||||
}
|
||||
while (getChildCount() < mNumPredictedAppsPerRow) {
|
||||
AllAppsGridAdapter.ViewHolder holder = mAdapter
|
||||
.onCreateViewHolder(this, AllAppsGridAdapter.VIEW_TYPE_ICON);
|
||||
BubbleTextView icon = (BubbleTextView) holder.itemView;
|
||||
LinearLayout.LayoutParams params =
|
||||
new LayoutParams(0, icon.getLayoutParams().height);
|
||||
params.weight = 1;
|
||||
icon.setLayoutParams(params);
|
||||
addView(icon);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
BubbleTextView icon = (BubbleTextView) getChildAt(i);
|
||||
icon.reset();
|
||||
if (mPredictedApps.size() > i) {
|
||||
icon.setVisibility(View.VISIBLE);
|
||||
icon.applyFromApplicationInfo(mPredictedApps.get(i));
|
||||
} else {
|
||||
// We need to update the appIndex of all the items.
|
||||
onAppsUpdated();
|
||||
icon.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,16 +147,4 @@ public class PredictionRowView extends LinearLayout {
|
||||
}
|
||||
return predictedApps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps out the old predicted apps with the new predicted apps, in place. This optimization
|
||||
* allows us to skip an entire relayout that would otherwise be called by notifyDataSetChanged.
|
||||
*
|
||||
* Note: This should only be called if the # of predicted apps is the same.
|
||||
* This method assumes that predicted apps are the first items in the adapter.
|
||||
*/
|
||||
private void swapInNewPredictedApps(List<AppInfo> apps) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -61,4 +61,6 @@ abstract class BaseFlags {
|
||||
|
||||
// When enabled shows a work profile tab in all apps
|
||||
public static final boolean ALL_APPS_TABS_ENABLED = false;
|
||||
// When enabled prediction row is rendered as it's own custom view
|
||||
public static final boolean ALL_APPS_PREDICTION_ROW_VIEW = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user