blob: 2295804e5a945d02bf46ab0892b662c860e508d8 [file] [log] [blame]
/*
* Copyright (C) 2008 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.browser;
import android.app.Activity;
import android.app.Fragment;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.provider.Browser;
import android.provider.BrowserContract.History;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebIconDatabase.IconListener;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.Toast;
/**
* Activity for displaying the browser's history, divided into
* days of viewing.
*/
public class BrowserHistoryPage extends Fragment
implements LoaderCallbacks<Cursor>, OnChildClickListener {
static final int LOADER_HISTORY = 1;
BookmarksHistoryCallbacks mCallbacks;
ExpandableListView mList;
View mEmptyView;
HistoryAdapter mAdapter;
boolean mDisableNewWindow;
HistoryItem mContextHeader;
// Implementation of WebIconDatabase.IconListener
class IconReceiver implements IconListener {
@Override
public void onReceivedIcon(String url, Bitmap icon) {
mAdapter.notifyDataSetChanged();
}
}
// Instance of IconReceiver
final IconReceiver mIconReceiver = new IconReceiver();
static interface HistoryQuery {
static final String[] PROJECTION = new String[] {
History._ID, // 0
History.DATE_LAST_VISITED, // 1
History.TITLE, // 2
History.URL, // 3
History.FAVICON, // 4
};
static final int INDEX_ID = 0;
static final int INDEX_DATE_LAST_VISITED = 1;
static final int INDEX_TITE = 2;
static final int INDEX_URL = 3;
static final int INDEX_FAVICON = 4;
}
private void copy(CharSequence text) {
ClipboardManager cm = (ClipboardManager) getActivity().getSystemService(
Context.CLIPBOARD_SERVICE);
cm.setText(text);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id) {
case LOADER_HISTORY: {
CursorLoader loader = new CursorLoader(getActivity(), History.CONTENT_URI,
HistoryQuery.PROJECTION, null, null, null);
return loader;
}
default: {
throw new IllegalArgumentException();
}
}
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
switch (loader.getId()) {
case LOADER_HISTORY: {
mAdapter.changeCursor(data);
// Add an empty view late, so it does not claim an empty
// history before the adapter is present
mList.setEmptyView(mEmptyView);
// Do not post the runnable if there is nothing in the list.
if (mList.getExpandableListAdapter().getGroupCount() > 0) {
mList.post(new Runnable() {
@Override
public void run() {
// In case the history gets cleared before this
// event happens
if (mList.getExpandableListAdapter().getGroupCount() > 0) {
mList.expandGroup(0);
}
}
});
}
break;
}
default: {
throw new IllegalArgumentException();
}
}
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setHasOptionsMenu(true);
Bundle args = getArguments();
mDisableNewWindow = args.getBoolean("disable_new_window", false);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallbacks = (BookmarksHistoryCallbacks) activity;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.history, container, false);
mList = (ExpandableListView) root.findViewById(android.R.id.list);
mList.setOnCreateContextMenuListener(this);
mList.setOnChildClickListener(this);
mAdapter = new HistoryAdapter(getActivity());
mList.setAdapter(mAdapter);
mEmptyView = root.findViewById(android.R.id.empty);
// Start the loader
getLoaderManager().initLoader(LOADER_HISTORY, null, this);
// Register to receive icons in case they haven't all been loaded.
CombinedBookmarkHistoryActivity.getIconListenerSet().addListener(mIconReceiver);
return root;
}
@Override
public void onDestroy() {
super.onDestroy();
CombinedBookmarkHistoryActivity.getIconListenerSet().removeListener(mIconReceiver);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.history, menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
menu.findItem(R.id.clear_history_menu_id).setVisible(
Browser.canClearHistory(getActivity().getContentResolver()));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.clear_history_menu_id:
Browser.clearHistory(getActivity().getContentResolver());
// BrowserHistoryPage is always a child of
// CombinedBookmarkHistoryActivity
mCallbacks.onRemoveParentChildRelationShips();
return true;
default:
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
ExpandableListContextMenuInfo i = (ExpandableListContextMenuInfo) menuInfo;
// Do not allow a context menu to come up from the group views.
if (!(i.targetView instanceof HistoryItem)) {
return;
}
// Inflate the menu
Activity parent = getActivity();
MenuInflater inflater = parent.getMenuInflater();
inflater.inflate(R.menu.historycontext, menu);
HistoryItem historyItem = (HistoryItem) i.targetView;
// Setup the header
if (mContextHeader == null) {
mContextHeader = new HistoryItem(parent);
} else if (mContextHeader.getParent() != null) {
((ViewGroup) mContextHeader.getParent()).removeView(mContextHeader);
}
historyItem.copyTo(mContextHeader);
menu.setHeaderView(mContextHeader);
// Only show open in new tab if it was not explicitly disabled
if (mDisableNewWindow) {
menu.findItem(R.id.new_window_context_menu_id).setVisible(false);
}
// For a bookmark, provide the option to remove it from bookmarks
if (historyItem.isBookmark()) {
MenuItem item = menu.findItem(R.id.save_to_bookmarks_menu_id);
item.setTitle(R.string.remove_from_bookmarks);
}
// decide whether to show the share link option
PackageManager pm = parent.getPackageManager();
Intent send = new Intent(Intent.ACTION_SEND);
send.setType("text/plain");
ResolveInfo ri = pm.resolveActivity(send, PackageManager.MATCH_DEFAULT_ONLY);
menu.findItem(R.id.share_link_context_menu_id).setVisible(ri != null);
super.onCreateContextMenu(menu, v, menuInfo);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
ExpandableListContextMenuInfo i =
(ExpandableListContextMenuInfo) item.getMenuInfo();
HistoryItem historyItem = (HistoryItem) i.targetView;
String url = historyItem.getUrl();
String title = historyItem.getName();
Activity activity = getActivity();
switch (item.getItemId()) {
case R.id.open_context_menu_id:
mCallbacks.onUrlSelected(url, false);
return true;
case R.id.new_window_context_menu_id:
mCallbacks.onUrlSelected(url, true);
return true;
case R.id.save_to_bookmarks_menu_id:
if (historyItem.isBookmark()) {
Bookmarks.removeFromBookmarks(activity, activity.getContentResolver(),
url, title);
} else {
Browser.saveBookmark(activity, title, url);
}
return true;
case R.id.share_link_context_menu_id:
Browser.sendString(activity, url,
activity.getText(R.string.choosertitle_sharevia).toString());
return true;
case R.id.copy_url_context_menu_id:
copy(url);
return true;
case R.id.delete_context_menu_id:
Browser.deleteFromHistory(activity.getContentResolver(), url);
return true;
case R.id.homepage_context_menu_id:
BrowserSettings.getInstance().setHomePage(activity, url);
Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show();
return true;
default:
break;
}
return super.onContextItemSelected(item);
}
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
if (v instanceof BookmarkItem) {
mCallbacks.onUrlSelected(((BookmarkItem) v).getUrl(), false);
return true;
}
return false;
}
private class HistoryAdapter extends DateSortedExpandableListAdapter {
HistoryAdapter(Context context) {
super(context, HistoryQuery.INDEX_DATE_LAST_VISITED);
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
BookmarkItem item;
if (null == convertView || !(convertView instanceof BookmarkItem)) {
item = new BookmarkItem(getContext());
// Add padding on the left so it will be indented from the
// arrows on the group views.
item.setPadding(item.getPaddingLeft() + 10,
item.getPaddingTop(),
item.getPaddingRight(),
item.getPaddingBottom());
} else {
item = (BookmarkItem) convertView;
}
// Bail early if the Cursor is closed.
if (!moveCursorToChildPosition(groupPosition, childPosition)) {
return item;
}
item.setName(getString(HistoryQuery.INDEX_TITE));
String url = getString(HistoryQuery.INDEX_URL);
item.setUrl(url);
byte[] data = getBlob(HistoryQuery.INDEX_FAVICON);
if (data != null) {
item.setFavicon(BitmapFactory.decodeByteArray(data, 0,
data.length));
} else {
item.setFavicon(CombinedBookmarkHistoryActivity
.getIconListenerSet().getFavicon(url));
}
return item;
}
}
}