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">
<TextView
android:id="@android:id/title"
- android:textAppearance="?android:attr/textAppearanceListItem"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_width="wrap_content"
- android:layout_weight="1"/>
+ 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" />
<ImageView
android:id="@android:id/icon"
- android:layout_width="@dimen/search_suggestion_item_image_size"
- android:layout_height="@dimen/search_suggestion_item_image_size"
- android:layout_marginStart="@dimen/search_suggestion_item_image_margin_start"
- android:layout_marginEnd="@dimen/search_suggestion_item_image_margin_end"
- android:scaleType="centerInside"
- android:src="@drawable/ic_search_history"/>
+ 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" />
</LinearLayout>
\ No newline at end of file
<!-- Suggestion item image margin start / end -->
<dimen name="search_suggestion_item_image_margin_start">32dp</dimen>
- <dimen name="search_suggestion_item_image_margin_end">16dp</dimen>
+ <dimen name="search_suggestion_item_image_margin_end">32dp</dimen>
<!-- Dimensions for Wifi Assistant Card -->
<dimen name="wifi_assistant_padding_top_bottom">16dp</dimen>
--- /dev/null
+/*
+ * 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<Void> {
+
+ 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;
+ }
+ }
+}
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));
}
}
@VisibleForTesting
String mQuery;
- private final SaveQueryRecorderCallback mSaveQueryRecorderCallback =
- new SaveQueryRecorderCallback();
+ private final SaveQueryCallback mSaveQueryCallback =
+ new SaveQueryCallback();
private boolean mNeverEnteredQuery = true;
private int mResultClickCount;
@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;
}
}
public void onSearchResultClicked() {
+ getLoaderManager().restartLoader(SaveQueryCallback.LOADER_ID_SAVE_QUERY_TASK, null,
+ mSaveQueryCallback);
mResultClickCount++;
}
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);
}
}
- private class SaveQueryRecorderCallback implements LoaderManager.LoaderCallbacks<Void> {
+ private class SaveQueryCallback implements LoaderManager.LoaderCallbacks<Void> {
// 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<Void> 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<Void> loader, Void data) {
-
+ switch (loader.getId()) {
+ case LOADER_ID_REMOVE_QUERY_TASK:
+ getLoaderManager().restartLoader(LOADER_ID_RECENTS, null, SearchFragment.this);
+ break;
+ }
}
@Override
@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() {
}
@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<? extends SearchResult> 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();
}
}
private Context mContext;
private SavedQueryViewHolder mHolder;
private View mView;
+ private View mTitleView;
+ private View mRemoveButton;
@Before
public void setUp() {
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);
}
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));
}
}
@Test
public void onLoadFinished_ShowsFeedback() {
-
when(mFeatureFactory.searchFeatureProvider
.getDatabaseSearchLoader(any(Context.class), anyString()))
.thenReturn(new MockDBLoader(RuntimeEnvironment.application));