Refactor all apps to depend on activity context.

The current AllAppsContainerView has been split into a base class and a
subclass for activities. The base class allows using all apps with an
activity context. A-Z and work profile tabs are supported, but search
and the hotseat still require an Activity.

Test: Manual. All apps should work the same.
Bug: 204696617
Change-Id: I3b146714bc11b3b3555d97623aab5d78ac836482
This commit is contained in:
Brian Isganitis
2022-01-14 23:15:47 -05:00
parent 46728f6481
commit 1664c9f418
26 changed files with 534 additions and 387 deletions

View File

@@ -0,0 +1,723 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.allapps;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.Process;
import android.os.UserManager;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowInsets;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.ColorUtils;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.Insettable;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.keyboard.FocusedItemDecorator;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.ScrimView;
import com.android.launcher3.views.SpringRelativeLayout;
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
import java.util.Arrays;
import java.util.List;
/**
* Base all apps view container.
*
* @param <T> Type of context inflating all apps.
*/
public abstract class BaseAllAppsContainerView<T extends Context & ActivityContext> extends
SpringRelativeLayout implements DragSource, Insettable, OnDeviceProfileChangeListener,
OnActivePageChangedListener, ScrimView.ScrimDrawingController {
private static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page";
public static final float PULL_MULTIPLIER = .02f;
public static final float FLING_VELOCITY_MULTIPLIER = 1200f;
private final Paint mHeaderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Rect mInsets = new Rect();
/** Context of an activity or window that is inflating this container. */
protected final T mActivityContext;
protected final List<AdapterHolder> mAH;
protected final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(
Process.myUserHandle());
private final SearchAdapterProvider<?> mMainAdapterProvider;
private final AllAppsStore mAllAppsStore = new AllAppsStore();
private final RecyclerView.OnScrollListener mScrollListener =
new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
updateHeaderScroll(((AllAppsRecyclerView) recyclerView).getCurrentScrollY());
}
};
private final WorkProfileManager mWorkManager;
private final Paint mNavBarScrimPaint;
private int mNavBarScrimHeight = 0;
private AllAppsPagedView mViewPager;
protected FloatingHeaderView mHeader;
protected boolean mUsingTabs;
private boolean mHasWorkApps;
protected RecyclerViewFastScroller mTouchHandler;
protected final Point mFastScrollerOffset = new Point();
private final int mScrimColor;
private final int mHeaderProtectionColor;
protected final float mHeaderThreshold;
private ScrimView mScrimView;
private int mHeaderColor;
private int mTabsProtectionAlpha;
protected BaseAllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mActivityContext = ActivityContext.lookupContext(context);
mMainAdapterProvider = createMainAdapterProvider();
mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
mHeaderThreshold = getResources().getDimensionPixelSize(
R.dimen.dynamic_grid_cell_border_spacing);
mHeaderProtectionColor = Themes.getAttrColor(context, R.attr.allappsHeaderProtectionColor);
mWorkManager = new WorkProfileManager(
mActivityContext.getSystemService(UserManager.class),
this,
Utilities.getPrefs(mActivityContext));
mAH = Arrays.asList(null, null);
mAH.set(AdapterHolder.MAIN, new AdapterHolder(false /* isWork */));
mAH.set(AdapterHolder.WORK, new AdapterHolder(true /* isWork */));
mNavBarScrimPaint = new Paint();
mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
mAllAppsStore.addUpdateListener(this::onAppsUpdated);
updateBackground(mActivityContext.getDeviceProfile());
}
/** Creates the adapter provider for the main section. */
protected abstract SearchAdapterProvider<?> createMainAdapterProvider();
/** The adapter provider for the main section. */
public final SearchAdapterProvider<?> getMainAdapterProvider() {
return mMainAdapterProvider;
}
@Override
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> sparseArray) {
try {
// Many slice view id is not properly assigned, and hence throws null
// pointer exception in the underneath method. Catching the exception
// simply doesn't restore these slice views. This doesn't have any
// user visible effect because because we query them again.
super.dispatchRestoreInstanceState(sparseArray);
} catch (Exception e) {
Log.e("AllAppsContainerView", "restoreInstanceState viewId = 0", e);
}
Bundle state = (Bundle) sparseArray.get(R.id.work_tab_state_id, null);
if (state != null) {
int currentPage = state.getInt(BUNDLE_KEY_CURRENT_PAGE, 0);
if (currentPage != 0 && mViewPager != null) {
mViewPager.setCurrentPage(currentPage);
rebindAdapters();
} else {
reset(true);
}
}
}
@Override
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
super.dispatchSaveInstanceState(container);
Bundle state = new Bundle();
state.putInt(BUNDLE_KEY_CURRENT_PAGE, getCurrentPage());
container.put(R.id.work_tab_state_id, state);
}
/**
* Sets the long click listener for icons
*/
public void setOnIconLongClickListener(OnLongClickListener listener) {
for (AdapterHolder holder : mAH) {
holder.adapter.setOnIconLongClickListener(listener);
}
}
public AllAppsStore getAppsStore() {
return mAllAppsStore;
}
public WorkProfileManager getWorkManager() {
return mWorkManager;
}
@Override
public void onDeviceProfileChanged(DeviceProfile dp) {
for (AdapterHolder holder : mAH) {
holder.adapter.setAppsPerRow(dp.numShownAllAppsColumns);
if (holder.mRecyclerView != null) {
// Remove all views and clear the pool, while keeping the data same. After this
// call, all the viewHolders will be recreated.
holder.mRecyclerView.swapAdapter(holder.mRecyclerView.getAdapter(), true);
holder.mRecyclerView.getRecycledViewPool().clear();
}
}
updateBackground(dp);
}
private void updateBackground(DeviceProfile deviceProfile) {
setBackground(deviceProfile.isTablet
? getContext().getDrawable(R.drawable.bg_all_apps_bottom_sheet)
: null);
}
private void onAppsUpdated() {
boolean hasWorkApps = false;
for (AppInfo app : mAllAppsStore.getApps()) {
if (mWorkManager.getMatcher().matches(app, null)) {
hasWorkApps = true;
break;
}
}
mHasWorkApps = hasWorkApps;
if (!mAH.get(AdapterHolder.MAIN).mAppsList.hasFilter()) {
rebindAdapters();
if (hasWorkApps) {
mWorkManager.reset();
}
}
}
/**
* Returns whether the view itself will handle the touch event or not.
*/
public boolean shouldContainerScroll(MotionEvent ev) {
// TODO(b/216203409) Support dragging down from bottom sheet divider, if present.
AllAppsRecyclerView rv = getActiveRecyclerView();
if (rv == null) {
return true;
}
if (rv.getScrollbar().getThumbOffsetY() >= 0
&& mActivityContext.getDragLayer().isEventOverView(rv.getScrollbar(), ev)) {
return false;
}
return rv.shouldContainerScroll(ev, mActivityContext.getDragLayer());
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
AllAppsRecyclerView rv = getActiveRecyclerView();
if (rv != null && rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(),
mFastScrollerOffset)) {
mTouchHandler = rv.getScrollbar();
} else {
mTouchHandler = null;
}
}
if (mTouchHandler != null) {
return mTouchHandler.handleTouchEvent(ev, mFastScrollerOffset);
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
AllAppsRecyclerView rv = getActiveRecyclerView();
if (rv != null && rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(),
mFastScrollerOffset)) {
mTouchHandler = rv.getScrollbar();
} else {
mTouchHandler = null;
}
}
if (mTouchHandler != null) {
mTouchHandler.handleTouchEvent(ev, mFastScrollerOffset);
return true;
}
return false;
}
/** Description of the container view based on its current state. */
public String getDescription() {
@StringRes int descriptionRes;
if (mUsingTabs) {
descriptionRes =
mViewPager.getNextPage() == 0
? R.string.all_apps_button_personal_label
: R.string.all_apps_button_work_label;
} else {
descriptionRes = R.string.all_apps_button_label;
}
return getContext().getString(descriptionRes);
}
/** The current recycler view visible in the container. */
public AllAppsRecyclerView getActiveRecyclerView() {
if (!mUsingTabs || mViewPager.getNextPage() == 0) {
return mAH.get(AdapterHolder.MAIN).mRecyclerView;
} else {
return mAH.get(AdapterHolder.WORK).mRecyclerView;
}
}
public LayoutInflater getLayoutInflater() {
return LayoutInflater.from(getContext());
}
/**
* Resets the state of AllApps.
*/
public void reset(boolean animate) {
for (int i = 0; i < mAH.size(); i++) {
if (mAH.get(i).mRecyclerView != null) {
mAH.get(i).mRecyclerView.scrollToTop();
}
}
if (isHeaderVisible()) {
mHeader.reset(animate);
}
// Reset the base recycler view after transitioning home.
updateHeaderScroll(0);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// This is a focus listener that proxies focus from a view into the list view. This is to
// work around the search box from getting first focus and showing the cursor.
setOnFocusChangeListener((v, hasFocus) -> {
if (hasFocus && getActiveRecyclerView() != null) {
getActiveRecyclerView().requestFocus();
}
});
mHeader = findViewById(R.id.all_apps_header);
rebindAdapters(true /* force */);
}
@Override
public void onDropCompleted(View target, DragObject d, boolean success) {
}
@Override
public void setInsets(Rect insets) {
mInsets.set(insets);
DeviceProfile grid = mActivityContext.getDeviceProfile();
for (int i = 0; i < mAH.size(); i++) {
mAH.get(i).mPadding.bottom = insets.bottom;
mAH.get(i).mPadding.left = mAH.get(i).mPadding.right = grid.allAppsLeftRightPadding;
mAH.get(i).applyPadding();
}
MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
mlp.topMargin = grid.isTablet ? insets.top : 0;
int leftRightMargin = grid.allAppsLeftRightMargin;
mlp.leftMargin = insets.left + leftRightMargin;
mlp.rightMargin = insets.right + leftRightMargin;
setLayoutParams(mlp);
if (grid.isVerticalBarLayout()) {
setPadding(grid.workspacePadding.left, 0, grid.workspacePadding.right, 0);
} else {
setPadding(0, 0, 0, 0);
}
InsettableFrameLayout.dispatchInsets(this, insets);
}
@Override
public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
if (Utilities.ATLEAST_Q) {
mNavBarScrimHeight = insets.getTappableElementInsets().bottom;
} else {
mNavBarScrimHeight = insets.getStableInsetBottom();
}
return super.dispatchApplyWindowInsets(insets);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mNavBarScrimHeight > 0) {
canvas.drawRect(0, getHeight() - mNavBarScrimHeight, getWidth(), getHeight(),
mNavBarScrimPaint);
}
}
protected void rebindAdapters() {
rebindAdapters(false /* force */);
}
protected void rebindAdapters(boolean force) {
boolean showTabs = showTabs();
if (showTabs == mUsingTabs && !force) {
return;
}
replaceRVContainer(showTabs);
mUsingTabs = showTabs;
mAllAppsStore.unregisterIconContainer(mAH.get(AdapterHolder.MAIN).mRecyclerView);
mAllAppsStore.unregisterIconContainer(mAH.get(AdapterHolder.WORK).mRecyclerView);
if (mUsingTabs) {
mAH.get(AdapterHolder.MAIN).setup(mViewPager.getChildAt(0), mPersonalMatcher);
mAH.get(AdapterHolder.WORK).setup(mViewPager.getChildAt(1), mWorkManager.getMatcher());
mAH.get(AdapterHolder.WORK).mRecyclerView.setId(R.id.apps_list_view_work);
mViewPager.getPageIndicator().setActiveMarker(AdapterHolder.MAIN);
findViewById(R.id.tab_personal)
.setOnClickListener((View view) -> {
if (mViewPager.snapToPage(AdapterHolder.MAIN)) {
mActivityContext.getStatsLogManager().logger()
.log(LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB);
}
});
findViewById(R.id.tab_work)
.setOnClickListener((View view) -> {
if (mViewPager.snapToPage(AdapterHolder.WORK)) {
mActivityContext.getStatsLogManager().logger()
.log(LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB);
}
});
onActivePageChanged(mViewPager.getNextPage());
} else {
mAH.get(AdapterHolder.MAIN).setup(findViewById(R.id.apps_list_view), null);
mAH.get(AdapterHolder.WORK).mRecyclerView = null;
}
setupHeader();
mAllAppsStore.registerIconContainer(mAH.get(AdapterHolder.MAIN).mRecyclerView);
mAllAppsStore.registerIconContainer(mAH.get(AdapterHolder.WORK).mRecyclerView);
}
protected boolean showTabs() {
return mHasWorkApps;
}
private void replaceRVContainer(boolean showTabs) {
for (AdapterHolder adapterHolder : mAH) {
if (adapterHolder.mRecyclerView != null) {
adapterHolder.mRecyclerView.setLayoutManager(null);
adapterHolder.mRecyclerView.setAdapter(null);
}
}
View oldView = getRecyclerViewContainer();
int index = indexOfChild(oldView);
removeView(oldView);
int layout = showTabs ? R.layout.all_apps_tabs : R.layout.all_apps_rv_layout;
View newView = getLayoutInflater().inflate(layout, this, false);
addView(newView, index);
if (showTabs) {
mViewPager = (AllAppsPagedView) newView;
mViewPager.initParentViews(this);
mViewPager.getPageIndicator().setOnActivePageChangedListener(this);
if (mWorkManager.attachWorkModeSwitch()) {
mWorkManager.getWorkModeSwitch().post(
() -> mAH.get(AdapterHolder.WORK).applyPadding());
}
} else {
mWorkManager.detachWorkModeSwitch();
mViewPager = null;
}
}
public View getRecyclerViewContainer() {
return mViewPager != null ? mViewPager : findViewById(R.id.apps_list_view);
}
@Override
public void onActivePageChanged(int currentActivePage) {
mHeader.setMainActive(currentActivePage == AdapterHolder.MAIN);
if (mAH.get(currentActivePage).mRecyclerView != null) {
mAH.get(currentActivePage).mRecyclerView.bindFastScrollbar();
}
reset(true /* animate */);
mWorkManager.onActivePageChanged(currentActivePage);
}
// Used by tests only
private boolean isDescendantViewVisible(int viewId) {
final View view = findViewById(viewId);
if (view == null) return false;
if (!view.isShown()) return false;
return view.getGlobalVisibleRect(new Rect());
}
@VisibleForTesting
public boolean isPersonalTabVisible() {
return isDescendantViewVisible(R.id.tab_personal);
}
@VisibleForTesting
public boolean isWorkTabVisible() {
return isDescendantViewVisible(R.id.tab_work);
}
public AlphabeticalAppsList<T> getApps() {
return mAH.get(AdapterHolder.MAIN).mAppsList;
}
public FloatingHeaderView getFloatingHeaderView() {
return mHeader;
}
@VisibleForTesting
public View getContentView() {
return mViewPager == null ? getActiveRecyclerView() : mViewPager;
}
/** The current page visible in all apps. */
public int getCurrentPage() {
return mViewPager != null ? mViewPager.getCurrentPage() : AdapterHolder.MAIN;
}
/** The scroll bar for the active recycler view. */
public RecyclerViewFastScroller getScrollBar() {
AllAppsRecyclerView rv = getActiveRecyclerView();
return rv == null ? null : rv.getScrollbar();
}
void setupHeader() {
mHeader.setVisibility(View.VISIBLE);
mHeader.setup(mAH, mAH.get(AdapterHolder.WORK).mRecyclerView == null);
int padding = mHeader.getMaxTranslation();
for (int i = 0; i < mAH.size(); i++) {
mAH.get(i).mPadding.top = padding;
mAH.get(i).applyPadding();
if (mAH.get(i).mRecyclerView != null) {
mAH.get(i).mRecyclerView.scrollToTop();
}
}
}
/** @see View#setVerticalFadingEdgeEnabled(boolean). */
public void setRecyclerViewVerticalFadingEdgeEnabled(boolean enabled) {
for (int i = 0; i < mAH.size(); i++) {
mAH.get(i).applyVerticalFadingEdgeEnabled(enabled);
}
}
public boolean isHeaderVisible() {
return mHeader != null && mHeader.getVisibility() == View.VISIBLE;
}
/**
* Adds an update listener to animator that adds springs to the animation.
*/
public void addSpringFromFlingUpdateListener(ValueAnimator animator,
float velocity /* release velocity */,
float progress /* portion of the distance to travel*/) {
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
float distance = (float) ((1 - progress) * getHeight()); // px
float settleVelocity = Math.min(0, distance
/ (AllAppsTransitionController.INTERP_COEFF * animator.getDuration())
+ velocity);
absorbSwipeUpVelocity(Math.max(1000, Math.abs(
Math.round(settleVelocity * FLING_VELOCITY_MULTIPLIER))));
}
});
}
/** Invoked when the container is pulled. */
public void onPull(float deltaDistance, float displacement) {
absorbPullDeltaDistance(PULL_MULTIPLIER * deltaDistance, PULL_MULTIPLIER * displacement);
// Current motion spec is to actually push and not pull
// on this surface. However, until EdgeEffect.onPush (b/190612804) is
// implemented at view level, we will simply pull
}
@Override
public void getDrawingRect(Rect outRect) {
super.getDrawingRect(outRect);
outRect.offset(0, (int) getTranslationY());
}
@Override
public void setTranslationY(float translationY) {
super.setTranslationY(translationY);
invalidateHeader();
}
public void setScrimView(ScrimView scrimView) {
mScrimView = scrimView;
}
@Override
public void drawOnScrim(Canvas canvas) {
if (!mHeader.isHeaderProtectionSupported()) return;
mHeaderPaint.setColor(mHeaderColor);
mHeaderPaint.setAlpha((int) (getAlpha() * Color.alpha(mHeaderColor)));
if (mHeaderPaint.getColor() != mScrimColor && mHeaderPaint.getColor() != 0) {
int bottom = getHeaderBottom();
canvas.drawRect(0, 0, canvas.getWidth(), bottom, mHeaderPaint);
int tabsHeight = getFloatingHeaderView().getPeripheralProtectionHeight();
if (mTabsProtectionAlpha > 0 && tabsHeight != 0) {
mHeaderPaint.setAlpha((int) (getAlpha() * mTabsProtectionAlpha));
canvas.drawRect(0, bottom, canvas.getWidth(), bottom + tabsHeight, mHeaderPaint);
}
}
}
/**
* redraws header protection
*/
public void invalidateHeader() {
if (mScrimView != null && mHeader.isHeaderProtectionSupported()) {
mScrimView.invalidate();
}
}
protected void updateHeaderScroll(int scrolledOffset) {
float prog = Utilities.boundToRange((float) scrolledOffset / mHeaderThreshold, 0f, 1f);
int headerColor = getHeaderColor(prog);
int tabsAlpha = mHeader.getPeripheralProtectionHeight() == 0 ? 0
: (int) (Utilities.boundToRange(
(scrolledOffset + mHeader.mSnappedScrolledY) / mHeaderThreshold, 0f, 1f)
* 255);
if (headerColor != mHeaderColor || mTabsProtectionAlpha != tabsAlpha) {
mHeaderColor = headerColor;
mTabsProtectionAlpha = tabsAlpha;
invalidateHeader();
}
}
protected int getHeaderColor(float blendRatio) {
return ColorUtils.blendARGB(mScrimColor, mHeaderProtectionColor, blendRatio);
}
protected int getHeaderBottom() {
return (int) getTranslationY();
}
/** Holds a {@link AllAppsGridAdapter} and related fields. */
public class AdapterHolder {
public static final int MAIN = 0;
public static final int WORK = 1;
private final boolean mIsWork;
public final AllAppsGridAdapter<T> adapter;
final LinearLayoutManager mLayoutManager;
final AlphabeticalAppsList<T> mAppsList;
final Rect mPadding = new Rect();
AllAppsRecyclerView mRecyclerView;
boolean mVerticalFadingEdge;
AdapterHolder(boolean isWork) {
mIsWork = isWork;
mAppsList = new AlphabeticalAppsList<>(mActivityContext, mAllAppsStore,
isWork ? mWorkManager.getAdapterProvider() : null);
BaseAdapterProvider[] adapterProviders =
isWork ? new BaseAdapterProvider[]{mMainAdapterProvider,
mWorkManager.getAdapterProvider()}
: new BaseAdapterProvider[]{mMainAdapterProvider};
adapter = new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), mAppsList,
adapterProviders);
mAppsList.setAdapter(adapter);
mLayoutManager = adapter.getLayoutManager();
}
void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
mAppsList.updateItemFilter(matcher);
mRecyclerView = (AllAppsRecyclerView) rv;
mRecyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
mRecyclerView.setApps(mAppsList);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(adapter);
mRecyclerView.setHasFixedSize(true);
// No animations will occur when changes occur to the items in this RecyclerView.
mRecyclerView.setItemAnimator(null);
mRecyclerView.addOnScrollListener(mScrollListener);
FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mRecyclerView);
mRecyclerView.addItemDecoration(focusedItemDecorator);
adapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
applyVerticalFadingEdgeEnabled(mVerticalFadingEdge);
applyPadding();
}
void applyPadding() {
if (mRecyclerView != null) {
int bottomOffset = 0;
if (mIsWork && mWorkManager.getWorkModeSwitch() != null) {
bottomOffset = mInsets.bottom + mWorkManager.getWorkModeSwitch().getHeight();
}
mRecyclerView.setPadding(mPadding.left, mPadding.top, mPadding.right,
mPadding.bottom + bottomOffset);
}
}
private void applyVerticalFadingEdgeEnabled(boolean enabled) {
mVerticalFadingEdge = enabled;
mAH.get(AdapterHolder.MAIN).mRecyclerView.setVerticalFadingEdgeEnabled(!mUsingTabs
&& mVerticalFadingEdge);
}
}
}