Bug 1278840 - FF for Android offers no way to remove arbitrary sites from history apart from top sites or recent history. r=sebastian
MozReview-Commit-ID: 2QAnzQLBd9q
--- a/mobile/android/base/java/org/mozilla/gecko/home/BrowserSearch.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/BrowserSearch.java
@@ -15,20 +15,18 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import android.content.SharedPreferences;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
-import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.PrefsHelper;
import org.mozilla.gecko.R;
import org.mozilla.gecko.SuggestClient;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
@@ -42,26 +40,30 @@ import org.mozilla.gecko.preferences.Gec
import org.mozilla.gecko.toolbar.AutocompleteHandler;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.StringUtils;
import org.mozilla.gecko.util.ThreadUtils;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
+import android.view.ContextMenu.ContextMenuInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.ContextMenu;
import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.WindowManager.LayoutParams;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
@@ -360,16 +362,44 @@ public class BrowserSearch extends HomeF
return mList.onItemLongClick(parent, view, position, id);
}
});
final ListSelectionListener listener = new ListSelectionListener();
mList.setOnItemSelectedListener(listener);
mList.setOnFocusChangeListener(listener);
+ mList.setContextMenuInfoFactory(new HomeContextMenuInfo.Factory() {
+ @Override
+ public HomeContextMenuInfo makeInfoForCursor(View view, int position, long id, Cursor cursor) {
+ final HomeContextMenuInfo info = new HomeContextMenuInfo(view, position, id);
+ info.url = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.URL));
+ info.title = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.TITLE));
+
+ int bookmarkId = cursor.getInt(cursor.getColumnIndexOrThrow(BrowserContract.Combined.BOOKMARK_ID));
+ info.bookmarkId = bookmarkId;
+
+ int historyId = cursor.getInt(cursor.getColumnIndexOrThrow(BrowserContract.Combined.HISTORY_ID));
+ info.historyId = historyId;
+
+ boolean isBookmark = bookmarkId != -1;
+ boolean isHistory = historyId != -1;
+
+ if (isBookmark && isHistory) {
+ info.itemType = HomeContextMenuInfo.RemoveItemType.COMBINED;
+ } else if (isBookmark) {
+ info.itemType = HomeContextMenuInfo.RemoveItemType.BOOKMARKS;
+ } else if (isHistory) {
+ info.itemType = HomeContextMenuInfo.RemoveItemType.HISTORY;
+ }
+
+ return info;
+ }
+ });
+
mList.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, android.view.KeyEvent event) {
final View selected = mList.getSelectedView();
if (selected instanceof SearchEngineRow) {
return selected.onKeyDown(keyCode, event);
}
@@ -380,16 +410,53 @@ public class BrowserSearch extends HomeF
registerForContextMenu(mList);
EventDispatcher.getInstance().registerGeckoThreadListener(this,
"SearchEngines:Data");
mSearchEngineBar.setOnSearchBarClickListener(this);
}
@Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
+ if (!(menuInfo instanceof HomeContextMenuInfo)) {
+ return;
+ }
+
+ HomeContextMenuInfo info = (HomeContextMenuInfo) menuInfo;
+
+ MenuInflater inflater = new MenuInflater(view.getContext());
+ inflater.inflate(R.menu.browsersearch_contextmenu, menu);
+
+ menu.setHeaderTitle(info.getDisplayTitle());
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ ContextMenuInfo menuInfo = item.getMenuInfo();
+ if (!(menuInfo instanceof HomeContextMenuInfo)) {
+ return false;
+ }
+
+ final HomeContextMenuInfo info = (HomeContextMenuInfo) menuInfo;
+ final Context context = getActivity();
+
+ final int itemId = item.getItemId();
+
+ if (itemId == R.id.browsersearch_remove) {
+ // Position for Top Sites grid items, but will always be -1 since this is only for BrowserSearch result
+ final int position = -1;
+
+ new RemoveItemByUrlTask(context, info.url, info.itemType, position).execute();
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Initialize the search adapter
mAdapter = new SearchAdapter(getActivity());
mList.setAdapter(mAdapter);
// Only create an instance when we need it
--- a/mobile/android/base/java/org/mozilla/gecko/home/HomeContextMenuInfo.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/HomeContextMenuInfo.java
@@ -24,17 +24,17 @@ public class HomeContextMenuInfo extends
public String title;
public boolean isFolder;
public int historyId = -1;
public int bookmarkId = -1;
public RemoveItemType itemType = null;
// Item type to be handled with "Remove" selection.
public static enum RemoveItemType {
- BOOKMARKS, HISTORY
+ BOOKMARKS, COMBINED, HISTORY
}
public HomeContextMenuInfo(View targetView, int position, long id) {
super(targetView, position, id);
}
public boolean hasBookmarkId() {
return bookmarkId > -1;
--- a/mobile/android/base/java/org/mozilla/gecko/home/HomeFragment.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/HomeFragment.java
@@ -405,53 +405,65 @@ public abstract class HomeFragment exten
mDB.unpinSite(cr, mPosition);
if (mDB.hideSuggestedSite(mUrl)) {
cr.notifyChange(SuggestedSites.CONTENT_URI, null);
}
}
switch (mType) {
case BOOKMARKS:
- SavedReaderViewHelper rch = SavedReaderViewHelper.getSavedReaderViewHelper(mContext);
- final boolean isReaderViewPage = rch.isURLCached(mUrl);
-
- final String extra;
- if (isReaderViewPage) {
- extra = "bookmark_reader";
- } else {
- extra = "bookmark";
- }
-
- Telemetry.sendUIEvent(TelemetryContract.Event.UNSAVE, TelemetryContract.Method.CONTEXT_MENU, extra);
- mDB.removeBookmarksWithURL(cr, mUrl);
-
- if (isReaderViewPage) {
- ReadingListHelper.removeCachedReaderItem(mUrl, mContext);
- }
-
+ removeBookmark(cr);
break;
case HISTORY:
- mDB.removeHistoryEntry(cr, mUrl);
+ removeHistory(cr);
+ break;
+
+ case COMBINED:
+ removeBookmark(cr);
+ removeHistory(cr);
break;
default:
Log.e(LOGTAG, "Can't remove item type " + mType.toString());
break;
}
return null;
}
@Override
public void onPostExecute(Void result) {
SnackbarBuilder.builder((Activity) mContext)
.message(R.string.page_removed)
.duration(Snackbar.LENGTH_LONG)
.buildAndShow();
}
+
+ private void removeBookmark(ContentResolver cr) {
+ SavedReaderViewHelper rch = SavedReaderViewHelper.getSavedReaderViewHelper(mContext);
+ final boolean isReaderViewPage = rch.isURLCached(mUrl);
+
+ final String extra;
+ if (isReaderViewPage) {
+ extra = "bookmark_reader";
+ } else {
+ extra = "bookmark";
+ }
+
+ Telemetry.sendUIEvent(TelemetryContract.Event.UNSAVE, TelemetryContract.Method.CONTEXT_MENU, extra);
+ mDB.removeBookmarksWithURL(cr, mUrl);
+
+ if (isReaderViewPage) {
+ ReadingListHelper.removeCachedReaderItem(mUrl, mContext);
+ }
+ }
+
+ private void removeHistory(ContentResolver cr) {
+ mDB.removeHistoryEntry(cr, mUrl);
+ }
}
private static class RemovePartnerBookmarkTask extends UIAsyncTask.WithoutParams<Void> {
private Context context;
private long bookmarkId;
public RemovePartnerBookmarkTask(Context context, long bookmarkId) {
super(ThreadUtils.getBackgroundHandler());
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/menu/browsersearch_contextmenu.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:id="@+id/browsersearch_remove"
+ android:title="@string/contextmenu_remove"/>
+
+</menu>