diff --git a/res/layout/widgets_search_bar.xml b/res/layout/widgets_search_bar.xml index 450e5f1ece..6f65e2bce6 100644 --- a/res/layout/widgets_search_bar.xml +++ b/res/layout/widgets_search_bar.xml @@ -9,7 +9,7 @@ android:background="@drawable/bg_widgets_searchbox" android:padding="12dp"> - No widgets available + + No search results diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java index 7fc965051d..4e6f17c384 100644 --- a/robolectric_tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java +++ b/robolectric_tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java @@ -24,9 +24,9 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import android.content.Context; import android.view.View; -import android.widget.EditText; import android.widget.ImageButton; +import com.android.launcher3.ExtendedEditText; import com.android.launcher3.search.SearchAlgorithm; import com.android.launcher3.widget.model.WidgetsListBaseEntry; @@ -45,7 +45,7 @@ public class WidgetsSearchBarControllerTest { private WidgetsSearchBarController mController; private Context mContext; - private EditText mEditText; + private ExtendedEditText mEditText; private ImageButton mCancelButton; @Mock private SearchModeListener mSearchModeListener; @@ -56,7 +56,7 @@ public class WidgetsSearchBarControllerTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; - mEditText = new EditText(mContext); + mEditText = new ExtendedEditText(mContext); mCancelButton = new ImageButton(mContext); mController = new WidgetsSearchBarController( mSearchAlgorithm, mEditText, mCancelButton, mSearchModeListener); @@ -116,11 +116,10 @@ public class WidgetsSearchBarControllerTest { } @Test - public void cancelSearch_shouldInformSearchModeListenerToExitSearch() { + public void cancelSearch_shouldInformSearchModeListenerToClearResultsAndExitSearch() { mCancelButton.performClick(); verify(mSearchModeListener).exitSearchMode(); - verifyNoMoreInteractions(mSearchModeListener); } @Test diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java index 92994be568..5747690ba6 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java +++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java @@ -57,6 +57,7 @@ import com.android.launcher3.widget.picker.search.WidgetsSearchBar; import com.android.launcher3.workprofile.PersonalWorkPagedView; import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener; +import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; @@ -161,8 +162,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet mAdapters.get(currentActivePage).mWidgetsRecyclerView; updateNoWidgetsView(currentAdapterHolder); - attachScrollbarToRecyclerView(currentRecyclerView); + resetExpandedHeaders(); } private void attachScrollbarToRecyclerView(WidgetsRecyclerView recyclerView) { @@ -180,6 +181,13 @@ public class WidgetsFullSheet extends BaseWidgetSheet mNoWidgetsView.setVisibility(isWidgetAvailable ? GONE : VISIBLE); } + private void updateNoSearchResultsView(boolean isVisible) { + mNoWidgetsView.setVisibility(isVisible ? VISIBLE : GONE); + if (isVisible) { + mNoWidgetsView.setText(R.string.no_search_results); + } + } + private void reset() { mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView.scrollToTop(); if (mHasWorkProfile) { @@ -323,10 +331,12 @@ public class WidgetsFullSheet extends BaseWidgetSheet if (mIsInSearchMode) return; setViewVisibilityBasedOnSearch(/*isInSearchMode= */ true); attachScrollbarToRecyclerView(mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView); + resetExpandedHeaders(); } @Override public void exitSearchMode() { + onSearchResults(new ArrayList<>()); setViewVisibilityBasedOnSearch(/*isInSearchMode=*/ false); if (mHasWorkProfile) { mViewPager.snapToPage(AdapterHolder.PRIMARY); @@ -337,6 +347,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet @Override public void onSearchResults(List entries) { mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.setWidgetsOnSearch(entries); + updateNoSearchResultsView( + mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.getItemCount() == 0); } private void setViewVisibilityBasedOnSearch(boolean isInSearchMode) { @@ -350,6 +362,12 @@ public class WidgetsFullSheet extends BaseWidgetSheet } mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView .setVisibility(mIsInSearchMode ? VISIBLE : GONE); + mNoWidgetsView.setVisibility(GONE); + } + + private void resetExpandedHeaders() { + mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.resetExpandedHeader(); + mAdapters.get(AdapterHolder.WORK).mWidgetsListAdapter.resetExpandedHeader(); } private void open(boolean animate) { diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java index 9009eb15c8..5346c1c18f 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java +++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java @@ -16,6 +16,7 @@ package com.android.launcher3.widget.picker; import android.content.Context; +import android.os.Process; import android.util.Log; import android.util.SparseArray; import android.view.LayoutInflater; @@ -81,7 +82,7 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC entry instanceof WidgetsListHeaderEntry || entry instanceof WidgetsListSearchHeaderEntry || new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user) - .equals(mWidgetsContentVisiblePackageUserKey); + .equals(mWidgetsContentVisiblePackageUserKey); @Nullable private Predicate mFilter = null; public WidgetsListAdapter(Context context, LayoutInflater layoutInflater, @@ -175,6 +176,14 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC mDiffReporter.process(mVisibleEntries, newVisibleEntries, mRowComparator); } + /** + * Resets any expanded widget header. + */ + public void resetExpandedHeader() { + mWidgetsContentVisiblePackageUserKey = null; + updateVisibleEntries(); + } + @Override public void onBindViewHolder(ViewHolder holder, int pos) { ViewHolderBinder viewHolderBinder = mViewHolderBinders.get(getItemViewType(pos)); @@ -258,7 +267,14 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC @Override public int compare(WidgetsListBaseEntry a, WidgetsListBaseEntry b) { - return mComparator.compare(a.mPkgItem.title.toString(), b.mPkgItem.title.toString()); + int i = mComparator.compare(a.mPkgItem.title.toString(), b.mPkgItem.title.toString()); + if (i != 0) { + return i; + } + // Prioritize entries from current user over other users if the entries are same. + if (a.mPkgItem.user.equals(b.mPkgItem.user)) return 0; + if (a.mPkgItem.user.equals(Process.myUserHandle())) return -1; + return 1; } } } diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java index 12d3f11919..b016b4f32c 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java +++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java @@ -220,8 +220,8 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch int totalItemsHeight = 0; for (int i = 0; i < untilIndex; i++) { WidgetsListBaseEntry entry = mAdapter.getItems().get(i); - if (entry instanceof WidgetsListHeaderEntry || - entry instanceof WidgetsListSearchHeaderEntry) { + if (entry instanceof WidgetsListHeaderEntry + || entry instanceof WidgetsListSearchHeaderEntry) { totalItemsHeight += mEstimatedWidgetListHeaderHeight; } else if (entry instanceof WidgetsListContentEntry) { totalItemsHeight += mLastVisibleWidgetContentTableHeight; diff --git a/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java b/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java index d68e87e3d6..5520826ab9 100644 --- a/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java +++ b/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java @@ -18,13 +18,13 @@ package com.android.launcher3.widget.picker.search; import android.content.Context; import android.util.AttributeSet; -import android.widget.EditText; import android.widget.ImageButton; import android.widget.LinearLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.launcher3.ExtendedEditText; import com.android.launcher3.R; import com.android.launcher3.search.SearchAlgorithm; import com.android.launcher3.widget.model.WidgetsListBaseEntry; @@ -36,7 +36,7 @@ import java.util.List; */ public class LauncherWidgetsSearchBar extends LinearLayout implements WidgetsSearchBar { private WidgetsSearchBarController mController; - private EditText mEditText; + private ExtendedEditText mEditText; private ImageButton mCancelButton; public LauncherWidgetsSearchBar(Context context) { diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java index 6c374842fd..60110977ed 100644 --- a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java +++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java @@ -22,9 +22,11 @@ import static android.view.View.VISIBLE; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; -import android.widget.EditText; +import android.view.KeyEvent; +import android.view.View; import android.widget.ImageButton; +import com.android.launcher3.ExtendedEditText; import com.android.launcher3.search.SearchAlgorithm; import com.android.launcher3.search.SearchCallback; import com.android.launcher3.widget.model.WidgetsListBaseEntry; @@ -35,22 +37,25 @@ import java.util.ArrayList; * Controller for a search bar with an edit text and a cancel button. */ public class WidgetsSearchBarController implements TextWatcher, - SearchCallback { + SearchCallback, ExtendedEditText.OnBackKeyListener, + View.OnKeyListener { private static final String TAG = "WidgetsSearchBarController"; private static final boolean DEBUG = false; protected SearchAlgorithm mSearchAlgorithm; - protected EditText mInput; + protected ExtendedEditText mInput; protected ImageButton mCancelButton; protected SearchModeListener mSearchModeListener; protected String mQuery; public WidgetsSearchBarController( - SearchAlgorithm algo, EditText editText, ImageButton cancelButton, - SearchModeListener searchModeListener) { + SearchAlgorithm algo, ExtendedEditText editText, + ImageButton cancelButton, SearchModeListener searchModeListener) { mSearchAlgorithm = algo; mInput = editText; mInput.addTextChangedListener(this); + mInput.setOnBackKeyListener(this); + mInput.setOnKeyListener(this); mCancelButton = cancelButton; mCancelButton.setOnClickListener(v -> clearSearchResult()); mSearchModeListener = searchModeListener; @@ -99,6 +104,7 @@ public class WidgetsSearchBarController implements TextWatcher, mSearchAlgorithm.cancel(/* interruptActiveRequests= */ true); mInput.getText().clear(); mInput.clearFocus(); + mInput.hideKeyboard(); mSearchModeListener.exitSearchMode(); } @@ -108,4 +114,21 @@ public class WidgetsSearchBarController implements TextWatcher, public void onDestroy() { mSearchAlgorithm.destroy(); } + + @Override + public boolean onBackKey() { + mInput.clearFocus(); + mInput.hideKeyboard(); + return true; + } + + @Override + public boolean onKey(View view, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) { + mInput.clearFocus(); + mInput.hideKeyboard(); + return true; + } + return false; + } }