OSDN Git Service

Add button to remove saved search query
authorFan Zhang <zhfan@google.com>
Wed, 15 Mar 2017 00:14:05 +0000 (17:14 -0700)
committerFan Zhang <zhfan@google.com>
Wed, 15 Mar 2017 17:43:10 +0000 (10:43 -0700)
TODO: move all saved query related logic into its own manager instead of
leaving them in SearchFragment.

Change-Id: I9635140eb507331246f9035a23138421cfa4b50a
Fix: 27391895
Test: make RunSettingsRoboTests

res/layout/search_saved_query_item.xml
res/values/dimens.xml
src/com/android/settings/search2/SavedQueryRemover.java [new file with mode: 0644]
src/com/android/settings/search2/SavedQueryViewHolder.java
src/com/android/settings/search2/SearchFragment.java
tests/robotests/src/com/android/settings/search2/SavedQueryRecorderAndRemoverTest.java [moved from tests/robotests/src/com/android/settings/search2/SavedQueryRecorderTest.java with 77% similarity]
tests/robotests/src/com/android/settings/search2/SavedQueryViewHolderTest.java
tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java

index 71c8482..50001a5 100644 (file)
     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
index fe5845a..f03a073 100755 (executable)
 
     <!-- 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>
diff --git a/src/com/android/settings/search2/SavedQueryRemover.java b/src/com/android/settings/search2/SavedQueryRemover.java
new file mode 100644 (file)
index 0000000..4395cb6
--- /dev/null
@@ -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<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;
+        }
+    }
+}
index 15d6f8b..6629c89 100644 (file)
@@ -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));
     }
 }
index 7eb9698..02ff2c8 100644 (file)
@@ -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<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
@@ -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<? 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();
     }
 }
index cc3cd33..5777609 100644 (file)
@@ -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));
     }
 }
index e7565c7..3e22d56 100644 (file)
@@ -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));