Bug 878136: Move ContextMenu functionality from AwesomeBar to BrowserApp. [r=lucasr]

This commit is contained in:
Sriram Ramasubramanian 2013-05-31 14:36:39 -07:00
parent e4b27b758c
commit 8f84acf5e2
5 changed files with 286 additions and 36 deletions

View File

@ -679,8 +679,8 @@ public class GeckoAppShell
createShortcut(aTitle, aURI, aURI, aIconData, aType);
}
// internal, for non-webapps
static void createShortcut(String aTitle, String aURI, Bitmap aBitmap, String aType) {
// for non-webapps
public static void createShortcut(String aTitle, String aURI, Bitmap aBitmap, String aType) {
createShortcut(aTitle, aURI, aURI, aBitmap, aType);
}
@ -1058,12 +1058,12 @@ public class GeckoAppShell
* @param title the title to use in <code>ACTION_SEND</code> intents.
* @return true if the activity started successfully; false otherwise.
*/
static boolean openUriExternal(String targetURI,
String mimeType,
String packageName,
String className,
String action,
String title) {
public static boolean openUriExternal(String targetURI,
String mimeType,
String packageName,
String className,
String action,
String title) {
final Context context = getContext();
final Intent intent = getOpenURIIntent(context, targetURI,
mimeType, action, title);

View File

@ -222,6 +222,8 @@ FENNEC_JAVA_FILES = \
gfx/VirtualLayer.java \
home/BookmarksPage.java \
home/BookmarkFolderView.java \
home/HomeFragment.java \
home/HomeListView.java \
home/HomePager.java \
home/HomePagerTabStrip.java \
home/FadedTextView.java \

View File

@ -9,9 +9,9 @@ import org.mozilla.gecko.R;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
import org.mozilla.gecko.db.BrowserContract.Combined;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.db.BrowserDB.URLColumns;
import org.mozilla.gecko.home.HomeListView.HomeContextMenuInfo;
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.ThreadUtils;
@ -20,11 +20,8 @@ import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.util.Pair;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
@ -36,14 +33,13 @@ import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import java.util.LinkedList;
/**
* A page in about:home that displays a ListView of bookmarks.
*/
public class BookmarksPage extends Fragment {
public class BookmarksPage extends HomeFragment {
public static final String LOGTAG = "GeckoBookmarksPage";
private int mFolderId = Bookmarks.FIXED_ROOT_ID;
@ -53,7 +49,7 @@ public class BookmarksPage extends Fragment {
private BookmarksQueryTask mQueryTask = null;
// The view shown by the fragment.
private ListView mList;
private HomeListView mList;
// Folder title for the currently shown list of bookmarks.
private BookmarkFolderView mFolderView;
@ -108,7 +104,7 @@ public class BookmarksPage extends Fragment {
// All list views are styled to look the same with a global activity theme.
// If the style of the list changes, inflate it from an XML.
mList = new ListView(container.getContext());
mList = new HomeListView(container.getContext());
return mList;
}
@ -240,29 +236,18 @@ public class BookmarksPage extends Fragment {
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
ListView list = (ListView) view;
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
Object selectedItem = list.getItemAtPosition(info.position);
Cursor cursor = (Cursor) selectedItem;
// Don't show the context menu for folders
if (cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks.TYPE)) == Bookmarks.TYPE_FOLDER) {
if (!(menuInfo instanceof HomeContextMenuInfo)) {
return;
}
String keyword = null;
int keywordCol = cursor.getColumnIndex(URLColumns.KEYWORD);
if (keywordCol != -1) {
keyword = cursor.getString(keywordCol);
HomeContextMenuInfo info = (HomeContextMenuInfo) menuInfo;
// Don't show the context menu for folders.
if (info.isFolder) {
return;
}
int id = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks._ID));
String url = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL));
String title = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.TITLE));
byte[] favicon = cursor.getBlob(cursor.getColumnIndexOrThrow(URLColumns.FAVICON));
int display = Combined.DISPLAY_NORMAL;
MenuInflater inflater = new MenuInflater(list.getContext());
MenuInflater inflater = new MenuInflater(view.getContext());
inflater.inflate(R.menu.awesomebar_contextmenu, menu);
// Show Open Private Tab if we're in private mode, Open New Tab otherwise
@ -275,10 +260,10 @@ public class BookmarksPage extends Fragment {
menu.findItem(R.id.open_private_tab).setVisible(isPrivate);
// Hide "Remove" item if there isn't a valid history ID
if (id < 0) {
if (info.rowId < 0) {
menu.findItem(R.id.remove_history).setVisible(false);
}
menu.setHeaderTitle(title);
menu.setHeaderTitle(info.title);
menu.findItem(R.id.remove_history).setVisible(false);
menu.findItem(R.id.open_in_reader).setVisible(false);

View File

@ -0,0 +1,167 @@
/* -*- 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;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.home.HomeListView.HomeContextMenuInfo;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.util.Log;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
/**
* HomeFragment is an empty fragment that can be added to the HomePager.
* Subclasses can add their own views.
*/
public class HomeFragment extends Fragment {
// Log Tag.
private static final String LOGTAG="GeckoHomeFragment";
// Share MIME type.
private static final String SHARE_MIME_TYPE = "text/plain";
// URL to Title replacement regex.
private static final String REGEX_URL_TO_TITLE = "^([a-z]+://)?(www\\.)?";
@Override
public boolean onContextItemSelected(MenuItem item) {
final Activity activity = getActivity();
HomeContextMenuInfo info = null;
try {
ContextMenuInfo menuInfo = item.getMenuInfo();
info = (HomeContextMenuInfo) menuInfo;
} catch(ClassCastException e) {
throw new IllegalArgumentException("ContextMenuInfo is not of type HomeContextMenuInfo");
}
switch(item.getItemId()) {
case R.id.share: {
if (info.url == null) {
Log.e(LOGTAG, "Can't share because URL is null");
break;
}
GeckoAppShell.openUriExternal(info.url, SHARE_MIME_TYPE, "", "",
Intent.ACTION_SEND, info.title);
return true;
}
case R.id.add_to_launcher: {
if (info.url == null) {
Log.e(LOGTAG, "Can't add to home screen because URL is null");
break;
}
Bitmap bitmap = null;
if (info.favicon != null && info.favicon.length > 0) {
bitmap = BitmapUtils.decodeByteArray(info.favicon);
}
String shortcutTitle = TextUtils.isEmpty(info.title) ? info.url.replaceAll(REGEX_URL_TO_TITLE, "") : info.title;
GeckoAppShell.createShortcut(shortcutTitle, info.url, bitmap, "");
return true;
}
case R.id.open_private_tab:
case R.id.open_new_tab: {
if (info.url == null) {
Log.e(LOGTAG, "Can't open in new tab because URL is null");
break;
}
int flags = Tabs.LOADURL_NEW_TAB;
if (item.getItemId() == R.id.open_private_tab)
flags |= Tabs.LOADURL_PRIVATE;
Tabs.getInstance().loadUrl(info.url, flags);
Toast.makeText(activity, R.string.new_tab_opened, Toast.LENGTH_SHORT).show();
return true;
}
case R.id.edit_bookmark: {
AlertDialog.Builder editPrompt = new AlertDialog.Builder(activity);
final View editView = LayoutInflater.from(activity).inflate(R.layout.bookmark_edit, null);
editPrompt.setTitle(R.string.bookmark_edit_title);
editPrompt.setView(editView);
final EditText nameText = ((EditText) editView.findViewById(R.id.edit_bookmark_name));
final EditText locationText = ((EditText) editView.findViewById(R.id.edit_bookmark_location));
final EditText keywordText = ((EditText) editView.findViewById(R.id.edit_bookmark_keyword));
nameText.setText(info.title);
locationText.setText(info.url);
keywordText.setText(info.keyword);
final int rowId = info.rowId;
editPrompt.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
(new UiAsyncTask<Void, Void, Void>(ThreadUtils.getBackgroundHandler()) {
@Override
public Void doInBackground(Void... params) {
String newUrl = locationText.getText().toString().trim();
String newKeyword = keywordText.getText().toString().trim();
BrowserDB.updateBookmark(activity.getContentResolver(), rowId, newUrl, nameText.getText().toString(), newKeyword);
return null;
}
@Override
public void onPostExecute(Void result) {
Toast.makeText(activity, R.string.bookmark_updated, Toast.LENGTH_SHORT).show();
}
}).execute();
}
});
editPrompt.setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
// do nothing
}
});
final AlertDialog dialog = editPrompt.create();
dialog.show();
return true;
}
case R.id.remove_bookmark: {
final int rowId = info.rowId;
(new UiAsyncTask<Void, Void, Void>(ThreadUtils.getBackgroundHandler()) {
@Override
public Void doInBackground(Void... params) {
BrowserDB.removeBookmark(activity.getContentResolver(), rowId);
return null;
}
@Override
public void onPostExecute(Void result) {
Toast.makeText(activity, R.string.bookmark_removed, Toast.LENGTH_SHORT).show();
}
}).execute();
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,96 @@
/* -*- 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;
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
import org.mozilla.gecko.db.BrowserContract.Combined;
import org.mozilla.gecko.db.BrowserDB.URLColumns;
import android.content.Context;
import android.database.Cursor;
import android.util.AttributeSet;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListView;
/**
* HomeListView is a custom extension of ListView, that packs a HomeContextMenuInfo
* when any of its rows is long pressed.
*/
public class HomeListView extends ListView
implements OnItemLongClickListener {
// ContextMenuInfo associated with the currently long pressed list item.
private HomeContextMenuInfo mContextMenuInfo;
public HomeListView(Context context) {
this(context, null);
}
public HomeListView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.listViewStyle);
}
public HomeListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setOnItemLongClickListener(this);
}
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Cursor cursor = (Cursor) parent.getItemAtPosition(position);
mContextMenuInfo = new HomeContextMenuInfo(view, position, id, cursor);
return showContextMenuForChild(HomeListView.this);
}
@Override
public ContextMenuInfo getContextMenuInfo() {
return mContextMenuInfo;
}
/**
* A ContextMenuInfo for HomeListView that adds details from the cursor.
*/
public static class HomeContextMenuInfo extends AdapterContextMenuInfo {
public int rowId;
public String url;
public byte[] favicon;
public String title;
public String keyword;
public int display;
public boolean isFolder;
public HomeContextMenuInfo(View targetView, int position, long id, Cursor cursor) {
super(targetView, position, id);
if (cursor == null) {
return;
}
isFolder = (cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks.TYPE)) == Bookmarks.TYPE_FOLDER);
if (isFolder) {
return;
}
int keywordCol = cursor.getColumnIndex(URLColumns.KEYWORD);
if (keywordCol != -1) {
keyword = cursor.getString(keywordCol);
} else {
keyword = null;
}
rowId = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks._ID));
url = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL));
title = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.TITLE));
favicon = cursor.getBlob(cursor.getColumnIndexOrThrow(URLColumns.FAVICON));
display = Combined.DISPLAY_NORMAL;
}
}
}