mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-03 17:36:49 +00:00
Refactors Search results into separate RV for Toast.
This will help enable transitions between A-Z apps lists and search results because both can be seen simultaneously and manipulated independently. Some high level items of the refactor: - SearchRecyclerView is added; logic that populated the main (personal) tab with search results was simply redirected to this RV instead. - BaseAllAppsContainerView added isSearching() method. Returns false, and ActivityAllAppsContainerView overrides (as search is handled there). - Renamed BaseRecyclerView to FastScrollRecyclerView to better describe what it does. SearchRecyclerView extends this, but returns false for supportsFastScrolling(). - AlphabeticalAppsList#mAllAppsStore is now optional, so the Search RV doesn't need to store/listen to apps. Note this doesn't affect the predicted app row which is still updated if one of the predicted apps is uninstalled (I tested this). Future work: - Determine why dispatchRestoreInstanceState is not called for BaseAllAppsContainerView. Save is called, e.g. on rotation. Effect of restore not called: rotating while searching goes back to A-Z list. - Keep suggested apps in Header while searching. Currently they are rendered in the SearchRV above search results, as before. - Potentially extract Personal/Work tabs to move independently of header. - AlphabeticalAppsList is a misleading name because it can also contains search results. However, things are pretty intertwined between that and BaseAllAppsAdapter (effectively a circular dependency), so I figured cleaning all that up was out of the immediate scope of this refactor, which is mainly meant to unblock transition work. Bug: 206905515 Test: Manually checked for regressions, ran tests. Change-Id: I4d3757c8a8f9b774956ca6be541dd4fcdad1de13
This commit is contained in:
@@ -80,7 +80,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
OnDeviceProfileChangeListener, OnActivePageChangedListener,
|
||||
ScrimView.ScrimDrawingController {
|
||||
|
||||
private static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page";
|
||||
protected 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;
|
||||
@@ -109,6 +109,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
private int mNavBarScrimHeight = 0;
|
||||
|
||||
private AllAppsPagedView mViewPager;
|
||||
private SearchRecyclerView mSearchRecyclerView;
|
||||
|
||||
protected FloatingHeaderView mHeader;
|
||||
private View mBottomSheetBackground;
|
||||
@@ -141,9 +142,10 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
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 */));
|
||||
mAH = Arrays.asList(null, null, null);
|
||||
mAH.set(AdapterHolder.MAIN, new AdapterHolder(AdapterHolder.MAIN));
|
||||
mAH.set(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK));
|
||||
mAH.set(AdapterHolder.SEARCH, new AdapterHolder(AdapterHolder.SEARCH));
|
||||
|
||||
mNavBarScrimPaint = new Paint();
|
||||
mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
|
||||
@@ -175,7 +177,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
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) {
|
||||
if (currentPage == AdapterHolder.WORK && mViewPager != null) {
|
||||
mViewPager.setCurrentPage(currentPage);
|
||||
rebindAdapters();
|
||||
} else {
|
||||
@@ -198,7 +200,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
*/
|
||||
public void setOnIconLongClickListener(OnLongClickListener listener) {
|
||||
for (AdapterHolder holder : mAH) {
|
||||
holder.adapter.setOnIconLongClickListener(listener);
|
||||
holder.mAdapter.setOnIconLongClickListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,7 +215,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
@Override
|
||||
public void onDeviceProfileChanged(DeviceProfile dp) {
|
||||
for (AdapterHolder holder : mAH) {
|
||||
holder.adapter.setAppsPerRow(dp.numShownAllAppsColumns);
|
||||
holder.mAdapter.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.
|
||||
@@ -237,7 +239,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
}
|
||||
}
|
||||
mHasWorkApps = hasWorkApps;
|
||||
if (!mAH.get(AdapterHolder.MAIN).mAppsList.hasFilter()) {
|
||||
if (!mAH.get(AdapterHolder.MAIN).mAppsList.hasSearchResults()) {
|
||||
rebindAdapters();
|
||||
if (hasWorkApps) {
|
||||
mWorkManager.reset();
|
||||
@@ -256,7 +258,11 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
if (mActivityContext.getDragLayer().isEventOverView(mBottomSheetHandleArea, ev)) {
|
||||
return true;
|
||||
}
|
||||
AllAppsRecyclerView rv = getActiveRecyclerView();
|
||||
if (isSearching()) {
|
||||
return mAH.get(AdapterHolder.SEARCH).mRecyclerView
|
||||
.shouldContainerScroll(ev, mActivityContext.getDragLayer());
|
||||
}
|
||||
AllAppsRecyclerView rv = getActiveAppsRecyclerView();
|
||||
if (rv == null) {
|
||||
return true;
|
||||
}
|
||||
@@ -270,7 +276,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
AllAppsRecyclerView rv = getActiveRecyclerView();
|
||||
AllAppsRecyclerView rv = getActiveAppsRecyclerView();
|
||||
if (rv != null && rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(),
|
||||
mFastScrollerOffset)) {
|
||||
mTouchHandler = rv.getScrollbar();
|
||||
@@ -287,7 +293,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
AllAppsRecyclerView rv = getActiveRecyclerView();
|
||||
AllAppsRecyclerView rv = getActiveAppsRecyclerView();
|
||||
if (rv != null && rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(),
|
||||
mFastScrollerOffset)) {
|
||||
mTouchHandler = rv.getScrollbar();
|
||||
@@ -320,8 +326,8 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
return getContext().getString(R.string.all_apps_button_label);
|
||||
}
|
||||
|
||||
/** The current recycler view visible in the container. */
|
||||
public AllAppsRecyclerView getActiveRecyclerView() {
|
||||
/** The current apps recycler view in the container (may be hidden for search results). */
|
||||
public AllAppsRecyclerView getActiveAppsRecyclerView() {
|
||||
if (!mUsingTabs || isPersonalTab()) {
|
||||
return mAH.get(AdapterHolder.MAIN).mRecyclerView;
|
||||
} else {
|
||||
@@ -370,12 +376,15 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
// 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();
|
||||
if (hasFocus && getActiveAppsRecyclerView() != null) {
|
||||
getActiveAppsRecyclerView().requestFocus();
|
||||
}
|
||||
});
|
||||
|
||||
mHeader = findViewById(R.id.all_apps_header);
|
||||
mSearchRecyclerView = findViewById(R.id.search_results_list_view);
|
||||
mAH.get(AdapterHolder.SEARCH).setup(mSearchRecyclerView,
|
||||
/* Filter out A-Z apps */ (itemInfo, componentName) -> false);
|
||||
rebindAdapters(true /* force */);
|
||||
|
||||
mBottomSheetBackground = findViewById(R.id.bottom_sheet_background);
|
||||
@@ -438,13 +447,19 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
}
|
||||
|
||||
protected void rebindAdapters(boolean force) {
|
||||
boolean showTabs = showTabs();
|
||||
updateSearchResultsVisibility();
|
||||
|
||||
boolean showTabs = shouldShowTabs();
|
||||
if (showTabs == mUsingTabs && !force) {
|
||||
return;
|
||||
}
|
||||
mUsingTabs = showTabs;
|
||||
replaceRVContainer(mUsingTabs);
|
||||
|
||||
if (isSearching()) {
|
||||
return;
|
||||
}
|
||||
|
||||
replaceAppsRVContainer(mUsingTabs);
|
||||
mAllAppsStore.unregisterIconContainer(mAH.get(AdapterHolder.MAIN).mRecyclerView);
|
||||
mAllAppsStore.unregisterIconContainer(mAH.get(AdapterHolder.WORK).mRecyclerView);
|
||||
|
||||
@@ -479,6 +494,17 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
mAllAppsStore.registerIconContainer(mAH.get(AdapterHolder.WORK).mRecyclerView);
|
||||
}
|
||||
|
||||
private void updateSearchResultsVisibility() {
|
||||
if (isSearching()) {
|
||||
getSearchRecyclerView().setVisibility(VISIBLE);
|
||||
getAppsRecyclerViewContainer().setVisibility(GONE);
|
||||
} else {
|
||||
getSearchRecyclerView().setVisibility(GONE);
|
||||
getAppsRecyclerViewContainer().setVisibility(VISIBLE);
|
||||
}
|
||||
mHeader.setActiveRV(getCurrentPage());
|
||||
}
|
||||
|
||||
private void setDeviceManagementResources() {
|
||||
if (mActivityContext.getStringCache() != null) {
|
||||
Button personalTab = findViewById(R.id.tab_personal);
|
||||
@@ -489,18 +515,23 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean showTabs() {
|
||||
protected boolean shouldShowTabs() {
|
||||
return mHasWorkApps;
|
||||
}
|
||||
|
||||
protected View replaceRVContainer(boolean showTabs) {
|
||||
for (AdapterHolder adapterHolder : mAH) {
|
||||
protected boolean isSearching() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected View replaceAppsRVContainer(boolean showTabs) {
|
||||
for (int i = AdapterHolder.MAIN; i <= AdapterHolder.WORK; i++) {
|
||||
AdapterHolder adapterHolder = mAH.get(i);
|
||||
if (adapterHolder.mRecyclerView != null) {
|
||||
adapterHolder.mRecyclerView.setLayoutManager(null);
|
||||
adapterHolder.mRecyclerView.setAdapter(null);
|
||||
}
|
||||
}
|
||||
View oldView = getRecyclerViewContainer();
|
||||
View oldView = getAppsRecyclerViewContainer();
|
||||
int index = indexOfChild(oldView);
|
||||
removeView(oldView);
|
||||
int layout = showTabs ? R.layout.all_apps_tabs : R.layout.all_apps_rv_layout;
|
||||
@@ -521,13 +552,17 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
return newView;
|
||||
}
|
||||
|
||||
public View getRecyclerViewContainer() {
|
||||
public View getAppsRecyclerViewContainer() {
|
||||
return mViewPager != null ? mViewPager : findViewById(R.id.apps_list_view);
|
||||
}
|
||||
|
||||
public SearchRecyclerView getSearchRecyclerView() {
|
||||
return mSearchRecyclerView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivePageChanged(int currentActivePage) {
|
||||
mHeader.setMainActive(currentActivePage == AdapterHolder.MAIN);
|
||||
mHeader.setActiveRV(currentActivePage);
|
||||
if (mAH.get(currentActivePage).mRecyclerView != null) {
|
||||
mAH.get(currentActivePage).mRecyclerView.bindFastScrollbar();
|
||||
}
|
||||
@@ -556,8 +591,8 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
return isDescendantViewVisible(R.id.tab_work);
|
||||
}
|
||||
|
||||
public AlphabeticalAppsList<T> getApps() {
|
||||
return mAH.get(AdapterHolder.MAIN).mAppsList;
|
||||
public AlphabeticalAppsList<T> getSearchResultList() {
|
||||
return mAH.get(AdapterHolder.SEARCH).mAppsList;
|
||||
}
|
||||
|
||||
public FloatingHeaderView getFloatingHeaderView() {
|
||||
@@ -566,17 +601,19 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
|
||||
@VisibleForTesting
|
||||
public View getContentView() {
|
||||
return mViewPager == null ? getActiveRecyclerView() : mViewPager;
|
||||
return mViewPager == null ? getActiveAppsRecyclerView() : mViewPager;
|
||||
}
|
||||
|
||||
/** The current page visible in all apps. */
|
||||
public int getCurrentPage() {
|
||||
return mViewPager != null ? mViewPager.getCurrentPage() : AdapterHolder.MAIN;
|
||||
return isSearching()
|
||||
? AdapterHolder.SEARCH
|
||||
: mViewPager == null ? AdapterHolder.MAIN : mViewPager.getCurrentPage();
|
||||
}
|
||||
|
||||
/** The scroll bar for the active recycler view. */
|
||||
public RecyclerViewFastScroller getScrollBar() {
|
||||
AllAppsRecyclerView rv = getActiveRecyclerView();
|
||||
AllAppsRecyclerView rv = getActiveAppsRecyclerView();
|
||||
return rv == null ? null : rv.getScrollbar();
|
||||
}
|
||||
|
||||
@@ -585,7 +622,9 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
mHeader.setup(
|
||||
mAH.get(AdapterHolder.MAIN).mRecyclerView,
|
||||
mAH.get(AdapterHolder.WORK).mRecyclerView,
|
||||
mAH.get(AdapterHolder.WORK).mRecyclerView == null);
|
||||
(SearchRecyclerView) mAH.get(AdapterHolder.SEARCH).mRecyclerView,
|
||||
getCurrentPage(),
|
||||
/* tabsHidden= */ mAH.get(AdapterHolder.WORK).mRecyclerView == null);
|
||||
|
||||
int padding = mHeader.getMaxTranslation();
|
||||
for (int i = 0; i < mAH.size(); i++) {
|
||||
@@ -696,39 +735,48 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
return ColorUtils.blendARGB(mScrimColor, mHeaderProtectionColor, blendRatio);
|
||||
}
|
||||
|
||||
protected abstract BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<T> mAppsList,
|
||||
protected abstract BaseAllAppsAdapter<T> createAdapter(AlphabeticalAppsList<T> mAppsList,
|
||||
BaseAdapterProvider[] adapterProviders);
|
||||
|
||||
protected int getHeaderBottom() {
|
||||
return (int) getTranslationY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view that denotes the visible part of all apps container view.
|
||||
*/
|
||||
public View getVisibleContainerView() {
|
||||
return mActivityContext.getDeviceProfile().isTablet ? mBottomSheetBackground : this;
|
||||
}
|
||||
|
||||
/** Holds a {@link BaseAllAppsAdapter} and related fields. */
|
||||
public class AdapterHolder {
|
||||
public static final int MAIN = 0;
|
||||
public static final int WORK = 1;
|
||||
public static final int SEARCH = 2;
|
||||
|
||||
private final boolean mIsWork;
|
||||
public final BaseAllAppsAdapter<T> adapter;
|
||||
private final int mType;
|
||||
public final BaseAllAppsAdapter<T> mAdapter;
|
||||
final RecyclerView.LayoutManager 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);
|
||||
AdapterHolder(int type) {
|
||||
mType = type;
|
||||
mAppsList = new AlphabeticalAppsList<>(mActivityContext,
|
||||
isSearch() ? null : mAllAppsStore,
|
||||
isWork() ? mWorkManager.getAdapterProvider() : null);
|
||||
|
||||
BaseAdapterProvider[] adapterProviders =
|
||||
isWork ? new BaseAdapterProvider[]{mMainAdapterProvider,
|
||||
isWork() ? new BaseAdapterProvider[]{mMainAdapterProvider,
|
||||
mWorkManager.getAdapterProvider()}
|
||||
: new BaseAdapterProvider[]{mMainAdapterProvider};
|
||||
|
||||
adapter = getAdapter(mAppsList, adapterProviders);
|
||||
mAppsList.setAdapter(adapter);
|
||||
mLayoutManager = adapter.getLayoutManager();
|
||||
mAdapter = createAdapter(mAppsList, adapterProviders);
|
||||
mAppsList.setAdapter(mAdapter);
|
||||
mLayoutManager = mAdapter.getLayoutManager();
|
||||
}
|
||||
|
||||
void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
|
||||
@@ -737,14 +785,14 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
mRecyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
|
||||
mRecyclerView.setApps(mAppsList);
|
||||
mRecyclerView.setLayoutManager(mLayoutManager);
|
||||
mRecyclerView.setAdapter(adapter);
|
||||
mRecyclerView.setAdapter(mAdapter);
|
||||
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());
|
||||
mAdapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
|
||||
applyVerticalFadingEdgeEnabled(mVerticalFadingEdge);
|
||||
applyPadding();
|
||||
}
|
||||
@@ -752,7 +800,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
void applyPadding() {
|
||||
if (mRecyclerView != null) {
|
||||
int bottomOffset = 0;
|
||||
if (mIsWork && mWorkManager.getWorkModeSwitch() != null) {
|
||||
if (isWork() && mWorkManager.getWorkModeSwitch() != null) {
|
||||
bottomOffset = mInsets.bottom + mWorkManager.getWorkModeSwitch().getHeight();
|
||||
}
|
||||
mRecyclerView.setPadding(mPadding.left, mPadding.top, mPadding.right,
|
||||
@@ -762,15 +810,15 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
|
||||
private void applyVerticalFadingEdgeEnabled(boolean enabled) {
|
||||
mVerticalFadingEdge = enabled;
|
||||
mAH.get(AdapterHolder.MAIN).mRecyclerView.setVerticalFadingEdgeEnabled(!mUsingTabs
|
||||
&& mVerticalFadingEdge);
|
||||
mRecyclerView.setVerticalFadingEdgeEnabled(!mUsingTabs && mVerticalFadingEdge);
|
||||
}
|
||||
|
||||
private boolean isWork() {
|
||||
return mType == WORK;
|
||||
}
|
||||
|
||||
private boolean isSearch() {
|
||||
return mType == SEARCH;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view that denotes the visible part of all apps container view.
|
||||
*/
|
||||
public View getVisibleContainerView() {
|
||||
return mActivityContext.getDeviceProfile().isTablet ? mBottomSheetBackground : this;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user