diff --git a/res/layout/search_saved_query_item.xml b/res/layout/search_saved_query_item.xml index 71c8482e737..50001a5ff62 100644 --- a/res/layout/search_saved_query_item.xml +++ b/res/layout/search_saved_query_item.xml @@ -20,26 +20,28 @@ android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?android:attr/selectableItemBackground" android:minHeight="?android:attr/listPreferredItemHeight" - android:gravity="center_vertical" - android:paddingStart="@dimen/preference_no_icon_padding_start" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"> + android:gravity="center_vertical"> + android:layout_weight="1" + android:text="test" + android:gravity="center_vertical" + android:background="?android:attr/selectableItemBackground" + android:paddingStart="@dimen/preference_no_icon_padding_start" + android:textAppearance="?android:attr/textAppearanceListItem" /> + android:background="?android:attr/selectableItemBackground" + android:layout_width="@dimen/dashboard_category_height" + android:layout_height="@dimen/dashboard_category_height" + android:paddingStart="@dimen/search_suggestion_item_image_margin_start" + android:paddingEnd="@dimen/search_suggestion_item_image_margin_end" + android:scaleType="center" + android:src="@drawable/ic_cross_grey_24dp" /> \ No newline at end of file diff --git a/res/values/dimens.xml b/res/values/dimens.xml index fe5845ab7ad..f03a0739e2f 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -137,7 +137,7 @@ 32dp - 16dp + 32dp 16dp diff --git a/src/com/android/settings/search2/SavedQueryRemover.java b/src/com/android/settings/search2/SavedQueryRemover.java new file mode 100644 index 00000000000..4395cb6c6a9 --- /dev/null +++ b/src/com/android/settings/search2/SavedQueryRemover.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 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.settings.search2; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.util.Log; + +import com.android.settings.search.IndexDatabaseHelper; +import com.android.settings.utils.AsyncLoader; + +import static com.android.settings.search.IndexDatabaseHelper.Tables.TABLE_SAVED_QUERIES; + +public class SavedQueryRemover extends AsyncLoader { + + private static final String LOG_TAG = "SavedQueryRemover"; + + private final String mQuery; + + public SavedQueryRemover(Context context, String query) { + super(context); + mQuery = query; + } + + @Override + public Void loadInBackground() { + final SQLiteDatabase database = getWritableDatabase(); + try { + // First, delete all saved queries that are the same + database.delete(TABLE_SAVED_QUERIES, + IndexDatabaseHelper.SavedQueriesColumns.QUERY + " = ?", + new String[]{mQuery}); + } catch (Exception e) { + Log.d(LOG_TAG, "Cannot update saved Search queries", e); + } + return null; + } + + @Override + protected void onDiscardResult(Void result) { + + } + + private SQLiteDatabase getWritableDatabase() { + try { + return IndexDatabaseHelper.getInstance(getContext()).getWritableDatabase(); + } catch (SQLiteException e) { + Log.e(LOG_TAG, "Cannot open writable database", e); + return null; + } + } +} diff --git a/src/com/android/settings/search2/SavedQueryViewHolder.java b/src/com/android/settings/search2/SavedQueryViewHolder.java index 15d6f8b63c7..6629c89de60 100644 --- a/src/com/android/settings/search2/SavedQueryViewHolder.java +++ b/src/com/android/settings/search2/SavedQueryViewHolder.java @@ -22,17 +22,18 @@ import android.widget.TextView; public class SavedQueryViewHolder extends SearchViewHolder { public final TextView titleView; + public final View removeButton; public SavedQueryViewHolder(View view) { super(view); titleView = view.findViewById(android.R.id.title); + removeButton = view.findViewById(android.R.id.icon); } @Override public void onBind(SearchFragment fragment, SearchResult result) { titleView.setText(result.title); - itemView.setOnClickListener(v -> { - fragment.onSavedQueryClicked(result.title); - }); + titleView.setOnClickListener(v -> fragment.onSavedQueryClicked(result.title)); + removeButton.setOnClickListener(v -> fragment.onRemoveSavedQueryClicked(result.title)); } } diff --git a/src/com/android/settings/search2/SearchFragment.java b/src/com/android/settings/search2/SearchFragment.java index 7eb9698a964..02ff2c8ff3f 100644 --- a/src/com/android/settings/search2/SearchFragment.java +++ b/src/com/android/settings/search2/SearchFragment.java @@ -74,8 +74,8 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O @VisibleForTesting String mQuery; - private final SaveQueryRecorderCallback mSaveQueryRecorderCallback = - new SaveQueryRecorderCallback(); + private final SaveQueryCallback mSaveQueryCallback = + new SaveQueryCallback(); private boolean mNeverEnteredQuery = true; private int mResultClickCount; @@ -218,8 +218,8 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O @Override public boolean onQueryTextSubmit(String query) { // Save submitted query. - getLoaderManager().restartLoader(SaveQueryRecorderCallback.LOADER_ID_SAVE_QUERY_TASK, null, - mSaveQueryRecorderCallback); + getLoaderManager().restartLoader(SaveQueryCallback.LOADER_ID_SAVE_QUERY_TASK, null, + mSaveQueryCallback); hideKeyboard(); return true; } @@ -264,6 +264,8 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O } public void onSearchResultClicked() { + getLoaderManager().restartLoader(SaveQueryCallback.LOADER_ID_SAVE_QUERY_TASK, null, + mSaveQueryCallback); mResultClickCount++; } @@ -275,6 +277,13 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O onQueryTextChange(queryString); } + public void onRemoveSavedQueryClicked(CharSequence title) { + final Bundle args = new Bundle(); + args.putString(SaveQueryCallback.ARG_REMOVE_QUERY, title.toString()); + getLoaderManager().restartLoader(SaveQueryCallback.LOADER_ID_REMOVE_QUERY_TASK, + args, mSaveQueryCallback); + } + private void restartLoaders() { final LoaderManager loaderManager = getLoaderManager(); mUnfinishedLoadersCount.set(NUM_QUERY_LOADERS); @@ -317,19 +326,31 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O } } - private class SaveQueryRecorderCallback implements LoaderManager.LoaderCallbacks { + private class SaveQueryCallback implements LoaderManager.LoaderCallbacks { // TODO: make a generic background task manager to handle one-off tasks like this one. private static final int LOADER_ID_SAVE_QUERY_TASK = 0; + private static final int LOADER_ID_REMOVE_QUERY_TASK = 1; + private static final String ARG_REMOVE_QUERY = "remove_query"; @Override public Loader onCreateLoader(int id, Bundle args) { - return new SavedQueryRecorder(getActivity(), mQuery); + switch (id) { + case LOADER_ID_SAVE_QUERY_TASK: + return new SavedQueryRecorder(getActivity(), mQuery); + case LOADER_ID_REMOVE_QUERY_TASK: + return new SavedQueryRemover(getActivity(), args.getString(ARG_REMOVE_QUERY)); + } + return null; } @Override public void onLoadFinished(Loader loader, Void data) { - + switch (loader.getId()) { + case LOADER_ID_REMOVE_QUERY_TASK: + getLoaderManager().restartLoader(LOADER_ID_RECENTS, null, SearchFragment.this); + break; + } } @Override diff --git a/tests/robotests/src/com/android/settings/search2/SavedQueryRecorderTest.java b/tests/robotests/src/com/android/settings/search2/SavedQueryRecorderAndRemoverTest.java similarity index 77% rename from tests/robotests/src/com/android/settings/search2/SavedQueryRecorderTest.java rename to tests/robotests/src/com/android/settings/search2/SavedQueryRecorderAndRemoverTest.java index 5374aae9aac..ae782790bc1 100644 --- a/tests/robotests/src/com/android/settings/search2/SavedQueryRecorderTest.java +++ b/tests/robotests/src/com/android/settings/search2/SavedQueryRecorderAndRemoverTest.java @@ -36,10 +36,11 @@ import static com.google.common.truth.Truth.assertThat; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) -public class SavedQueryRecorderTest { +public class SavedQueryRecorderAndRemoverTest { private Context mContext; private SavedQueryRecorder mRecorder; + private SavedQueryRemover mRemover; @Before public void setUp() { @@ -52,16 +53,25 @@ public class SavedQueryRecorderTest { } @Test - public void canSaveQueryToDb() { + public void canSaveAndRemoveQuery() { final String query = "test"; mRecorder = new SavedQueryRecorder(mContext, query); + mRemover = new SavedQueryRemover(mContext, query); + // Record a new query and load all queries from DB mRecorder.loadInBackground(); - final SavedQueryLoader loader = new SavedQueryLoader(mContext); List results = loader.loadInBackground(); + // Should contain the newly recorded query assertThat(results.size()).isEqualTo(1); assertThat(results.get(0).title).isEqualTo(query); + + // Remove the query and load all queries from DB + mRemover.loadInBackground(); + results = loader.loadInBackground(); + + // Saved query list should be empty because it's removed. + assertThat(results).isEmpty(); } } diff --git a/tests/robotests/src/com/android/settings/search2/SavedQueryViewHolderTest.java b/tests/robotests/src/com/android/settings/search2/SavedQueryViewHolderTest.java index cc3cd33e40e..57776093083 100644 --- a/tests/robotests/src/com/android/settings/search2/SavedQueryViewHolderTest.java +++ b/tests/robotests/src/com/android/settings/search2/SavedQueryViewHolderTest.java @@ -45,6 +45,8 @@ public class SavedQueryViewHolderTest { private Context mContext; private SavedQueryViewHolder mHolder; private View mView; + private View mTitleView; + private View mRemoveButton; @Before public void setUp() { @@ -52,6 +54,8 @@ public class SavedQueryViewHolderTest { mContext = RuntimeEnvironment.application; mView = LayoutInflater.from(mContext) .inflate(R.layout.search_saved_query_item, null); + mTitleView = mView.findViewById(android.R.id.title); + mRemoveButton = mView.findViewById(android.R.id.icon); mHolder = new SavedQueryViewHolder(mView); } @@ -60,8 +64,10 @@ public class SavedQueryViewHolderTest { final SearchResult result = mock(SearchResult.class); mHolder.onBind(mSearchFragment, result); - mView.performClick(); + mTitleView.performClick(); + mRemoveButton.performClick(); verify(mSearchFragment).onSavedQueryClicked(any(CharSequence.class)); + verify(mSearchFragment).onRemoveSavedQueryClicked(any(CharSequence.class)); } } diff --git a/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java b/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java index e7565c72b0e..3e22d5661f8 100644 --- a/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java +++ b/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java @@ -276,7 +276,6 @@ public class SearchFragmentTest { @Test public void onLoadFinished_ShowsFeedback() { - when(mFeatureFactory.searchFeatureProvider .getDatabaseSearchLoader(any(Context.class), anyString())) .thenReturn(new MockDBLoader(RuntimeEnvironment.application));