5eb66d8abb
All of the all apps search support is in this class which is also being refactored to depend on ActivityContext. At the end of this refactor, this class can be merged with BaseAllAppsContainerView. Test: Manual Bug: 216683257 Change-Id: I8cbf21c8d9ce97cc60e9846cfe8c2a7bcb800a01
263 lines
8.9 KiB
Java
263 lines
8.9 KiB
Java
/*
|
|
* Copyright (C) 2022 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 android.content.Context;
|
|
import android.content.Intent;
|
|
import android.util.AttributeSet;
|
|
import android.view.KeyEvent;
|
|
import android.view.MotionEvent;
|
|
import android.view.View;
|
|
import android.widget.RelativeLayout;
|
|
|
|
import androidx.core.graphics.ColorUtils;
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
|
|
import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
|
|
import com.android.launcher3.R;
|
|
import com.android.launcher3.Utilities;
|
|
import com.android.launcher3.allapps.search.SearchAdapterProvider;
|
|
import com.android.launcher3.config.FeatureFlags;
|
|
import com.android.launcher3.util.PackageManagerHelper;
|
|
import com.android.launcher3.views.AppLauncher;
|
|
|
|
import java.util.Objects;
|
|
|
|
/**
|
|
* All apps container view with search support for use in a dragging activity.
|
|
*
|
|
* @param <T> Type of context inflating all apps.
|
|
*/
|
|
public class ActivityAllAppsContainerView<T extends Context & AppLauncher
|
|
& DeviceProfileListenable> extends BaseAllAppsContainerView<T> {
|
|
|
|
protected SearchUiManager mSearchUiManager;
|
|
/**
|
|
* View that defines the search box. Result is rendered inside the recycler view defined in the
|
|
* base class.
|
|
*/
|
|
private View mSearchContainer;
|
|
/** {@code true} when rendered view is in search state instead of the scroll state. */
|
|
private boolean mIsSearching;
|
|
|
|
public ActivityAllAppsContainerView(Context context) {
|
|
this(context, null);
|
|
}
|
|
|
|
public ActivityAllAppsContainerView(Context context, AttributeSet attrs) {
|
|
this(context, attrs, 0);
|
|
}
|
|
|
|
public ActivityAllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
|
|
super(context, attrs, defStyleAttr);
|
|
}
|
|
|
|
public SearchUiManager getSearchUiManager() {
|
|
return mSearchUiManager;
|
|
}
|
|
|
|
public View getSearchView() {
|
|
return mSearchContainer;
|
|
}
|
|
|
|
/** Updates all apps container with the latest search query. */
|
|
public void setLastSearchQuery(String query) {
|
|
Intent marketSearchIntent = PackageManagerHelper.getMarketSearchIntent(
|
|
mActivityContext, query);
|
|
OnClickListener marketSearchClickListener = (v) -> mActivityContext.startActivitySafely(v,
|
|
marketSearchIntent, null);
|
|
for (int i = 0; i < mAH.size(); i++) {
|
|
mAH.get(i).adapter.setLastSearchQuery(query, marketSearchClickListener);
|
|
}
|
|
mIsSearching = true;
|
|
rebindAdapters();
|
|
mHeader.setCollapsed(true);
|
|
}
|
|
|
|
/** Invoke when the current search session is finished. */
|
|
public void onClearSearchResult() {
|
|
mIsSearching = false;
|
|
mHeader.setCollapsed(false);
|
|
rebindAdapters();
|
|
mHeader.reset(false);
|
|
}
|
|
|
|
/** Invoke when the search results change. */
|
|
public void onSearchResultsChanged() {
|
|
for (int i = 0; i < mAH.size(); i++) {
|
|
if (mAH.get(i).mRecyclerView != null) {
|
|
mAH.get(i).mRecyclerView.onSearchResultsChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected final SearchAdapterProvider<?> createMainAdapterProvider() {
|
|
return mActivityContext.createSearchAdapterProvider(this);
|
|
}
|
|
|
|
@Override
|
|
public boolean shouldContainerScroll(MotionEvent ev) {
|
|
// IF the MotionEvent is inside the search box, and the container keeps on receiving
|
|
// touch input, container should move down.
|
|
if (mActivityContext.getDragLayer().isEventOverView(mSearchContainer, ev)) {
|
|
return true;
|
|
}
|
|
return super.shouldContainerScroll(ev);
|
|
}
|
|
|
|
@Override
|
|
public void reset(boolean animate) {
|
|
super.reset(animate);
|
|
// Reset the search bar after transitioning home.
|
|
mSearchUiManager.resetSearch();
|
|
}
|
|
|
|
@Override
|
|
protected void onFinishInflate() {
|
|
super.onFinishInflate();
|
|
mSearchContainer = findViewById(R.id.search_container_all_apps);
|
|
mSearchUiManager = (SearchUiManager) mSearchContainer;
|
|
mSearchUiManager.initializeSearch(this);
|
|
}
|
|
|
|
@Override
|
|
public boolean dispatchKeyEvent(KeyEvent event) {
|
|
mSearchUiManager.preDispatchKeyEvent(event);
|
|
return super.dispatchKeyEvent(event);
|
|
}
|
|
|
|
@Override
|
|
public String getDescription() {
|
|
if (!mUsingTabs && mIsSearching) {
|
|
return getContext().getString(R.string.all_apps_search_results);
|
|
} else {
|
|
return super.getDescription();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected boolean showTabs() {
|
|
return super.showTabs() && !mIsSearching;
|
|
}
|
|
|
|
@Override
|
|
protected void rebindAdapters(boolean force) {
|
|
super.rebindAdapters(force);
|
|
if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()
|
|
|| getMainAdapterProvider().getDecorator() == null) {
|
|
return;
|
|
}
|
|
|
|
RecyclerView.ItemDecoration decoration = getMainAdapterProvider().getDecorator();
|
|
mAH.stream()
|
|
.map(adapterHolder -> adapterHolder.mRecyclerView)
|
|
.filter(Objects::nonNull)
|
|
.forEach(v -> {
|
|
v.removeItemDecoration(decoration); // Remove in case it is already added.
|
|
v.addItemDecoration(decoration);
|
|
});
|
|
}
|
|
|
|
@Override
|
|
protected View replaceRVContainer(boolean showTabs) {
|
|
View rvContainer = super.replaceRVContainer(showTabs);
|
|
if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
|
|
alignParentTop(rvContainer);
|
|
layoutAboveSearchContainer(rvContainer);
|
|
} else {
|
|
layoutBelowSearchContainer(rvContainer);
|
|
}
|
|
return rvContainer;
|
|
}
|
|
|
|
@Override
|
|
void setupHeader() {
|
|
super.setupHeader();
|
|
if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
|
|
alignParentTop(mHeader);
|
|
} else {
|
|
layoutBelowSearchContainer(mHeader);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void updateHeaderScroll(int scrolledOffset) {
|
|
super.updateHeaderScroll(scrolledOffset);
|
|
if (mSearchUiManager.getEditText() == null) {
|
|
return;
|
|
}
|
|
|
|
float prog = Utilities.boundToRange((float) scrolledOffset / mHeaderThreshold, 0f, 1f);
|
|
boolean bgVisible = mSearchUiManager.getBackgroundVisibility();
|
|
if (scrolledOffset == 0 && !mIsSearching) {
|
|
bgVisible = true;
|
|
} else if (scrolledOffset > mHeaderThreshold) {
|
|
bgVisible = false;
|
|
}
|
|
mSearchUiManager.setBackgroundVisibility(bgVisible, 1 - prog);
|
|
}
|
|
|
|
@Override
|
|
protected int getHeaderColor(float blendRatio) {
|
|
return ColorUtils.setAlphaComponent(
|
|
super.getHeaderColor(blendRatio),
|
|
(int) (mSearchContainer.getAlpha() * 255));
|
|
}
|
|
|
|
@Override
|
|
protected int getHeaderBottom() {
|
|
if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
|
|
return super.getHeaderBottom();
|
|
}
|
|
return super.getHeaderBottom() + mSearchContainer.getBottom();
|
|
}
|
|
|
|
private void layoutBelowSearchContainer(View v) {
|
|
if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) {
|
|
return;
|
|
}
|
|
RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams();
|
|
layoutParams.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
|
|
layoutParams.removeRule(RelativeLayout.ABOVE);
|
|
layoutParams.addRule(RelativeLayout.BELOW, R.id.search_container_all_apps);
|
|
}
|
|
|
|
private void layoutAboveSearchContainer(View v) {
|
|
if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) {
|
|
return;
|
|
}
|
|
RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams();
|
|
layoutParams.addRule(RelativeLayout.ABOVE, R.id.search_container_all_apps);
|
|
}
|
|
|
|
private void alignParentTop(View v) {
|
|
if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) {
|
|
return;
|
|
}
|
|
RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams();
|
|
layoutParams.removeRule(RelativeLayout.BELOW);
|
|
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
|
}
|
|
|
|
@Override
|
|
protected BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<T> mAppsList,
|
|
BaseAdapterProvider[] adapterProviders) {
|
|
return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), mAppsList,
|
|
adapterProviders);
|
|
}
|
|
}
|