mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-27 23:36:47 +00:00
Bug fixes for widget picker search.
SearchBarController - Use Extended Edit Text to handle close keyboard action well. - On press enter while search remove focus from bar and hide keyboard. - On cancel button press hide keyboard and also reset search targets to empty so that on next search session the previous results dont flash (show for a short time before reflecting users query). WidgetsFullSheet - Make sure expanded header are reset when user leaves personal/work recycler views. Search recycler view resets its expanded header on every search already. - Show 'no search results' view if no search result present. - Update WidgetListBaseRowEntryComparator to show personal profile widgets first. Test: Tested prototype locally. Bug: b/157286785 Change-Id: Ibaa208c4091783e14ac0887caf559e867185df5a
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
android:background="@drawable/bg_widgets_searchbox"
|
||||
android:padding="12dp">
|
||||
|
||||
<EditText
|
||||
<com.android.launcher3.ExtendedEditText
|
||||
android:id="@+id/widgets_search_bar_edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -84,6 +84,9 @@
|
||||
<!-- Text shown when there is no widgets shown in the popup view showing all available widgets
|
||||
installed on the device. [CHAR_LIMIT=none] -->
|
||||
<string name="no_widgets_available">No widgets available</string>
|
||||
<!-- Text shown when there are no matching widget search results for user's search query.
|
||||
[CHAR_LIMIT=none] -->
|
||||
<string name="no_search_results">No search results</string>
|
||||
|
||||
<!-- All Apps -->
|
||||
<!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<WidgetsListBaseEntry> 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) {
|
||||
|
||||
@@ -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<ViewHolder> implements OnHeaderC
|
||||
entry instanceof WidgetsListHeaderEntry
|
||||
|| entry instanceof WidgetsListSearchHeaderEntry
|
||||
|| new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user)
|
||||
.equals(mWidgetsContentVisiblePackageUserKey);
|
||||
.equals(mWidgetsContentVisiblePackageUserKey);
|
||||
@Nullable private Predicate<WidgetsListBaseEntry> mFilter = null;
|
||||
|
||||
public WidgetsListAdapter(Context context, LayoutInflater layoutInflater,
|
||||
@@ -175,6 +176,14 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> 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<ViewHolder> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<WidgetsListBaseEntry> {
|
||||
SearchCallback<WidgetsListBaseEntry>, ExtendedEditText.OnBackKeyListener,
|
||||
View.OnKeyListener {
|
||||
private static final String TAG = "WidgetsSearchBarController";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
protected SearchAlgorithm<WidgetsListBaseEntry> mSearchAlgorithm;
|
||||
protected EditText mInput;
|
||||
protected ExtendedEditText mInput;
|
||||
protected ImageButton mCancelButton;
|
||||
protected SearchModeListener mSearchModeListener;
|
||||
protected String mQuery;
|
||||
|
||||
public WidgetsSearchBarController(
|
||||
SearchAlgorithm<WidgetsListBaseEntry> algo, EditText editText, ImageButton cancelButton,
|
||||
SearchModeListener searchModeListener) {
|
||||
SearchAlgorithm<WidgetsListBaseEntry> 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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user