Bug 1291751 - Implement ASSearchActivity for bookmarks/history search draft
authorAndrzej Hunt <ahunt@mozilla.com>
Wed, 03 Aug 2016 09:34:01 -0700
changeset 398734 39093e5343e6ee82eb830c68810e069953f70a04
parent 398733 93bd8d84c2961d04c6994bfb403c845591487326
child 398735 f2a73956cdda63c55355a3611064afcc63fbd96d
push id25610
push userahunt@mozilla.com
push dateTue, 09 Aug 2016 17:01:51 +0000
bugs1291751
milestone51.0a1
Bug 1291751 - Implement ASSearchActivity for bookmarks/history search MozReview-Commit-ID: 9NyLP6PtKmJ
mobile/android/base/AndroidManifest.xml.in
mobile/android/base/java/org/mozilla/gecko/home/activitystream/search/ASSearchActivity.java
mobile/android/base/java/org/mozilla/gecko/home/activitystream/search/ASSearchResultsAdapter.java
mobile/android/base/locales/en-US/android_strings.dtd
mobile/android/base/moz.build
mobile/android/base/resources/drawable/as_search_bg.xml
mobile/android/base/resources/layout/as_search_activity.xml
mobile/android/base/strings.xml.in
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -273,16 +273,19 @@
         <activity android:name="org.mozilla.gecko.preferences.GeckoPreferences"
                   android:theme="@style/Gecko.Preferences"
                   android:configChanges="orientation|screenSize|locale|layoutDirection"
                   android:excludeFromRecents="true"/>
 
         <activity android:name="org.mozilla.gecko.home.activitystream.ASDetailActivity"
                   android:theme="@style/Gecko"/>
 
+        <activity android:name="org.mozilla.gecko.home.activitystream.search.ASSearchActivity"
+                  android:theme="@style/Gecko"/>
+
         <provider android:name="org.mozilla.gecko.db.BrowserProvider"
                   android:authorities="@ANDROID_PACKAGE_NAME@.db.browser"
                   android:exported="false"/>
 
         <provider android:name="org.mozilla.gecko.distribution.PartnerBookmarksProviderProxy"
                   android:authorities="@ANDROID_PACKAGE_NAME@.partnerbookmarks"
                   android:exported="false"/>
 
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/home/activitystream/search/ASSearchActivity.java
@@ -0,0 +1,145 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+package org.mozilla.gecko.home.activitystream.search;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.LinearLayoutManager;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.View;
+import android.widget.EditText;
+
+import org.mozilla.gecko.GeckoProfile;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.db.BrowserDB;
+import org.mozilla.gecko.home.CombinedHistoryRecyclerView;
+import org.mozilla.gecko.home.HomePager;
+import org.mozilla.gecko.home.activitystream.ASOpenURLDelegate;
+import org.mozilla.gecko.widget.RecyclerViewClickSupport;
+
+import java.util.EnumSet;
+
+public class ASSearchActivity extends AppCompatActivity implements HomePager.OnUrlOpenListener {
+    public static final String ACTIVITY_ARG_BOOKMARKS_MODE = "mode_bookmarks";
+
+    private static final String LOADER_ARG_KEY_CONSTRAINT = "constraint";
+
+    private CombinedHistoryRecyclerView resultsList;
+
+    @Override
+    public void onUrlOpen(String url, EnumSet<Flags> flags) {
+        ASOpenURLDelegate.openURL(this, url, flags);
+    }
+
+    private static class SearchLoader extends CursorLoader {
+        final String constraint;
+
+        public SearchLoader(Context context, String constraint) {
+            super(context);
+
+            this.constraint = constraint;
+        }
+
+        @Override
+        public Cursor loadInBackground() {
+            if (constraint == null || constraint.length() == 0) {
+                // We don't want to show any results when the query string is empty
+                return null;
+            }
+
+            // TODO: this currently retrieves history and bookmarks (the combined table), we want to be able to get
+            // just one or the other, so lets add some flags to do that?
+            // (We can probably keep using the combined table, and filter based on bookmark
+            // ID and history ID?)
+            return GeckoProfile.get(getContext()).getDB().filter(getContext().getContentResolver(),
+                    constraint,
+                    50,
+                    EnumSet.noneOf(BrowserDB.FilterFlags.class));
+        }
+    }
+
+    private class CursorLoaderCallbacks implements LoaderManager.LoaderCallbacks<Cursor> {
+        @Override
+        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+            final String constraint;
+            if (args != null) {
+                constraint = args.getString(LOADER_ARG_KEY_CONSTRAINT);
+            } else {
+                constraint = null;
+            }
+
+            return new SearchLoader(getApplicationContext(), constraint);
+        }
+
+        @Override
+        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+            ((ASSearchResultsAdapter) resultsList.getAdapter()).swapCursor(data);
+        }
+
+        @Override
+        public void onLoaderReset(Loader<Cursor> loader) {
+            ((ASSearchResultsAdapter) resultsList.getAdapter()).swapCursor(null);
+        }
+    }
+
+
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.as_search_activity);
+
+        findViewById(R.id.as_search_back).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                finish();
+            }
+        });
+
+        resultsList = (CombinedHistoryRecyclerView) findViewById(R.id.as_search_results);
+
+        resultsList.setOnHistoryClickedListener(this);
+        resultsList.setLayoutManager(new LinearLayoutManager(this));
+        resultsList.setAdapter(new ASSearchResultsAdapter());
+
+        // The long click support in CombineddHistoryRecyclerView makes various assumptions
+        // which do not apply to our view and adapter. We don't need long-click support
+        // for search results so we can just disable it completely for now.
+        RecyclerViewClickSupport.addTo(resultsList).setOnItemLongClickListener(null);
+
+        final CursorLoaderCallbacks callbacks = new CursorLoaderCallbacks();
+        getSupportLoaderManager().initLoader(0, null, callbacks);
+
+        final EditText searchEntry = (EditText) findViewById(R.id.as_search_entry);
+
+        if (getIntent().getBooleanExtra(ACTIVITY_ARG_BOOKMARKS_MODE, false)) {
+            searchEntry.setHint(R.string.as_search_in_bookmarks);
+        } else {
+            searchEntry.setHint(R.string.as_search_in_history);
+        }
+
+        searchEntry.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {
+                Bundle data = new Bundle();
+                data.putString(LOADER_ARG_KEY_CONSTRAINT, s.toString());
+
+                getSupportLoaderManager().restartLoader(0, data, callbacks);
+            }
+
+            @Override
+            public void afterTextChanged(Editable s) {}
+        });
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/home/activitystream/search/ASSearchResultsAdapter.java
@@ -0,0 +1,52 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+package org.mozilla.gecko.home.activitystream.search;
+
+import android.database.Cursor;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.home.CombinedHistoryItem;
+import org.mozilla.gecko.home.TwoLinePageRow;
+
+class ASSearchResultsAdapter extends RecyclerView.Adapter<CombinedHistoryItem.BookmarkHistoryItem> {
+    private Cursor cursor = null;
+
+    @Override
+    public CombinedHistoryItem.BookmarkHistoryItem onCreateViewHolder(ViewGroup parent, int viewType) {
+        final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+
+        final TwoLinePageRow row = (TwoLinePageRow) inflater.inflate(R.layout.home_item_row, parent, false);
+        return new CombinedHistoryItem.BookmarkHistoryItem(row);
+    }
+
+    @Override
+    public void onBindViewHolder(CombinedHistoryItem.BookmarkHistoryItem holder, int position) {
+        cursor.moveToPosition(position);
+        holder.bind(cursor);
+    }
+
+    @Override
+    public int getItemCount() {
+        if (cursor != null) {
+            return cursor.getCount();
+        } else {
+            return 0;
+        }
+    }
+
+    public void swapCursor(Cursor c) {
+        cursor = c;
+
+        notifyDataSetChanged();
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return CombinedHistoryItem.ItemType.HISTORY.ordinal();
+    }
+}
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -826,8 +826,10 @@ just addresses the organization to follo
 <!ENTITY helper_first_offline_bookmark_title "Read offline">
 <!ENTITY helper_first_offline_bookmark_message "Find your Reader View items in Bookmarks, even offline.">
 <!ENTITY helper_first_offline_bookmark_button "Go to Bookmarks">
 
 <!ENTITY helper_triple_readerview_open_title "Available offline">
 <!ENTITY helper_triple_readerview_open_message "Bookmark Reader View items to read them offline.">
 <!ENTITY helper_triple_readerview_open_button "Add to Bookmarks">
 
+<!ENTITY as_search_in_bookmarks "Search in Bookmarks">
+<!ENTITY as_search_in_history "Search in History">
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -438,16 +438,18 @@ gbjar.sources += ['java/org/mozilla/geck
     'health/HealthRecorder.java',
     'health/SessionInformation.java',
     'health/StubbedHealthRecorder.java',
     'home/activitystream/ActivityStream.java',
     'home/activitystream/ASCombinedHistoryAdapter.java',
     'home/activitystream/ASCombinedHistoryPanel.java',
     'home/activitystream/ASDetailActivity.java',
     'home/activitystream/ASOpenURLDelegate.java',
+    'home/activitystream/search/ASSearchActivity.java',
+    'home/activitystream/search/ASSearchResultsAdapter.java',
     'home/BookmarkFolderView.java',
     'home/BookmarkScreenshotRow.java',
     'home/BookmarksListAdapter.java',
     'home/BookmarksListView.java',
     'home/BookmarksPanel.java',
     'home/BrowserSearch.java',
     'home/ClientsAdapter.java',
     'home/CombinedHistoryAdapter.java',
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/drawable/as_search_bg.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#363B40"/>
+    <corners android:radius="2dip"/>
+</shape>
\ No newline at end of file
copy from mobile/android/base/resources/layout/as_detail_activity.xml
copy to mobile/android/base/resources/layout/as_search_activity.xml
--- a/mobile/android/base/resources/layout/as_detail_activity.xml
+++ b/mobile/android/base/resources/layout/as_search_activity.xml
@@ -1,51 +1,42 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              xmlns:app="http://schemas.android.com/apk/res-auto"
               android:orientation="vertical"
               android:layout_width="match_parent"
               android:layout_height="match_parent">
 
     <LinearLayout
         android:id="@+id/topbar"
         android:orientation="horizontal"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:background="@color/about_page_header_grey"
         android:layout_gravity="top"
         android:layout_marginBottom="1dp">
 
-        <android.support.design.widget.TabLayout
-            android:id="@+id/as_detail_tablayout"
-            android:layout_width="0dp"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            android:layout_gravity="left"
-            android:paddingLeft="12dp"
-            android:paddingRight="12dp"
-            app:tabSelectedTextColor="@color/placeholder_grey"
-            app:tabTextColor="@color/tab_text_color"
-            app:tabMode="scrollable"
-            app:tabIndicatorHeight="4dp"
-            app:tabIndicatorColor="#ff9400" />
-
         <ImageView
             android:layout_width="42dp"
             android:layout_height="42dp"
             android:padding="10dp"
-            android:src="@drawable/ab_search"
-            android:id="@+id/as_search_button"/>
+            android:src="@drawable/ic_menu_back"
+            android:id="@+id/as_search_back"/>
 
-        <ImageView
-            android:layout_width="42dp"
-            android:layout_height="42dp"
-            android:padding="14dp"
-            android:src="@drawable/tab_close"
-            android:id="@+id/as_close_button"/>
+        <EditText
+            android:id="@+id/as_search_entry"
+            style="@style/UrlBar.Button"
+            android:layout_margin="3dp"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="match_parent"
+            android:paddingLeft="8dp"
+            android:background="@drawable/as_search_bg"
+            android:textColor="@android:color/white"
+            android:textColorHint="@color/about_page_header_grey"
+            android:paddingRight="8dp"/>
 
     </LinearLayout>
 
-    <android.support.v4.view.ViewPager
-        android:id="@+id/as_pager"
+    <org.mozilla.gecko.home.CombinedHistoryRecyclerView
+        android:id="@+id/as_search_results"
         android:layout_width="match_parent"
-        android:layout_height="match_parent" />
+        android:layout_height="wrap_content"/>
 </LinearLayout>
\ No newline at end of file
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -629,9 +629,11 @@
   <string name="helper_first_offline_bookmark_title">&helper_first_offline_bookmark_title;</string>
   <string name="helper_first_offline_bookmark_message">&helper_first_offline_bookmark_message;</string>
   <string name="helper_first_offline_bookmark_button">&helper_first_offline_bookmark_button;</string>
 
   <string name="helper_triple_readerview_open_title">&helper_triple_readerview_open_title;</string>
   <string name="helper_triple_readerview_open_message">&helper_triple_readerview_open_message;</string>
   <string name="helper_triple_readerview_open_button">&helper_triple_readerview_open_button;</string>
 
+  <string name="as_search_in_bookmarks">&as_search_in_bookmarks;</string>
+  <string name="as_search_in_history">&as_search_in_history;</string>
 </resources>