blob: 23fcc5addcd4387227851bca709b25fa6566e117 [file] [log] [blame]
The Android Open Source Project0c908882009-03-03 19:32:16 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.browser;
18
19import android.app.Activity;
20import android.app.AlertDialog;
21import android.content.DialogInterface;
22import android.content.Intent;
Ben Murdoch328ea872009-09-16 13:33:29 +010023import android.content.SharedPreferences;
24import android.content.SharedPreferences.Editor;
The Android Open Source Project0c908882009-03-03 19:32:16 -080025import android.graphics.Bitmap;
Patrick Scotte09761e2009-03-24 20:43:37 -070026import android.graphics.BitmapFactory;
27import android.graphics.Canvas;
28import android.graphics.Color;
29import android.graphics.Paint;
Patrick Scott3918d442009-08-04 13:22:29 -040030import android.graphics.Path;
31import android.graphics.PorterDuff;
32import android.graphics.PorterDuffXfermode;
Patrick Scotte09761e2009-03-24 20:43:37 -070033import android.graphics.RectF;
The Android Open Source Project0c908882009-03-03 19:32:16 -080034import android.net.Uri;
35import android.os.Bundle;
36import android.os.Handler;
37import android.os.Message;
38import android.os.ServiceManager;
39import android.provider.Browser;
40import android.text.IClipboard;
41import android.util.Log;
42import android.view.ContextMenu;
43import android.view.KeyEvent;
Leon Scroggins892df312009-07-14 14:48:02 -040044import android.view.LayoutInflater;
The Android Open Source Project0c908882009-03-03 19:32:16 -080045import android.view.Menu;
46import android.view.MenuInflater;
47import android.view.MenuItem;
48import android.view.View;
49import android.view.ViewGroup;
Leon Scrogginsa5d669e2009-08-05 14:07:58 -040050import android.view.ViewGroup.LayoutParams;
51import android.view.ViewStub;
The Android Open Source Project0c908882009-03-03 19:32:16 -080052import android.view.ContextMenu.ContextMenuInfo;
53import android.widget.AdapterView;
Leon Scroggins89c6d362009-07-15 16:54:37 -040054import android.widget.GridView;
The Android Open Source Project0c908882009-03-03 19:32:16 -080055import android.widget.ListView;
Leon Scrogginsfeb941d2009-05-28 17:27:38 -040056import android.widget.Toast;
The Android Open Source Project0c908882009-03-03 19:32:16 -080057
Ben Murdoch328ea872009-09-16 13:33:29 +010058/*package*/ enum BookmarkViewMode { NONE, GRID, LIST }
The Android Open Source Project0c908882009-03-03 19:32:16 -080059/**
60 * View showing the user's bookmarks in the browser.
61 */
62public class BrowserBookmarksPage extends Activity implements
63 View.OnCreateContextMenuListener {
64
Ben Murdoch328ea872009-09-16 13:33:29 +010065 private BookmarkViewMode mViewMode = BookmarkViewMode.NONE;
Leon Scroggins89c6d362009-07-15 16:54:37 -040066 private GridView mGridPage;
Leon Scroggins892df312009-07-14 14:48:02 -040067 private View mVerticalList;
The Android Open Source Project0c908882009-03-03 19:32:16 -080068 private BrowserBookmarksAdapter mBookmarksAdapter;
69 private static final int BOOKMARKS_SAVE = 1;
Leon Scroggins190095d2009-08-17 17:01:38 -040070 private boolean mDisableNewWindow;
The Android Open Source Project0c908882009-03-03 19:32:16 -080071 private BookmarkItem mContextHeader;
72 private AddNewBookmark mAddHeader;
73 private boolean mCanceled = false;
74 private boolean mCreateShortcut;
Leon Scrogginsa5d669e2009-08-05 14:07:58 -040075 private boolean mMostVisited;
76 private View mEmptyView;
The Android Open Source Project0c908882009-03-03 19:32:16 -080077 // XXX: There is no public string defining this intent so if Home changes
78 // the value, we have to update this string.
79 private static final String INSTALL_SHORTCUT =
80 "com.android.launcher.action.INSTALL_SHORTCUT";
81
82 private final static String LOGTAG = "browser";
Ben Murdoch328ea872009-09-16 13:33:29 +010083 private final static String PREF_BOOKMARK_VIEW_MODE = "pref_bookmark_view_mode";
84 private final static String PREF_MOST_VISITED_VIEW_MODE = "pref_most_visited_view_mode";
The Android Open Source Project0c908882009-03-03 19:32:16 -080085
86 @Override
87 public boolean onContextItemSelected(MenuItem item) {
88 // It is possible that the view has been canceled when we get to
89 // this point as back has a higher priority
90 if (mCanceled) {
91 return true;
92 }
93 AdapterView.AdapterContextMenuInfo i =
94 (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
95 // If we have no menu info, we can't tell which item was selected.
96 if (i == null) {
97 return true;
98 }
99
100 switch (item.getItemId()) {
101 case R.id.new_context_menu_id:
102 saveCurrentPage();
103 break;
104 case R.id.open_context_menu_id:
105 loadUrl(i.position);
106 break;
107 case R.id.edit_context_menu_id:
108 editBookmark(i.position);
109 break;
110 case R.id.shortcut_context_menu_id:
Patrick Scott3918d442009-08-04 13:22:29 -0400111 final Intent send = createShortcutIntent(i.position);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800112 send.setAction(INSTALL_SHORTCUT);
113 sendBroadcast(send);
114 break;
115 case R.id.delete_context_menu_id:
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400116 if (mMostVisited) {
117 Browser.deleteFromHistory(getContentResolver(),
118 getUrl(i.position));
119 refreshList();
120 } else {
121 displayRemoveBookmarkDialog(i.position);
122 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800123 break;
124 case R.id.new_window_context_menu_id:
125 openInNewWindow(i.position);
126 break;
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400127 case R.id.share_link_context_menu_id:
The Android Open Source Project0c908882009-03-03 19:32:16 -0800128 Browser.sendString(BrowserBookmarksPage.this, getUrl(i.position));
129 break;
130 case R.id.copy_url_context_menu_id:
131 copy(getUrl(i.position));
Leon Scrogginsfeb941d2009-05-28 17:27:38 -0400132 break;
133 case R.id.homepage_context_menu_id:
134 BrowserSettings.getInstance().setHomePage(this,
135 getUrl(i.position));
136 Toast.makeText(this, R.string.homepage_set,
137 Toast.LENGTH_LONG).show();
138 break;
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400139 // Only for the Most visited page
140 case R.id.save_to_bookmarks_menu_id:
Leon Scrogginsc1f57592009-08-14 14:16:10 -0400141 boolean isBookmark;
142 String name;
143 String url;
Ben Murdoch328ea872009-09-16 13:33:29 +0100144 if (mViewMode == BookmarkViewMode.GRID) {
Leon Scrogginsc1f57592009-08-14 14:16:10 -0400145 isBookmark = mBookmarksAdapter.getIsBookmark(i.position);
146 name = mBookmarksAdapter.getTitle(i.position);
147 url = mBookmarksAdapter.getUrl(i.position);
148 } else {
149 HistoryItem historyItem = ((HistoryItem) i.targetView);
150 isBookmark = historyItem.isBookmark();
151 name = historyItem.getName();
152 url = historyItem.getUrl();
153 }
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400154 // If the site is bookmarked, the item becomes remove from
155 // bookmarks.
Leon Scrogginsc1f57592009-08-14 14:16:10 -0400156 if (isBookmark) {
157 Bookmarks.removeFromBookmarks(this, getContentResolver(), url);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400158 } else {
Leon Scrogginsc1f57592009-08-14 14:16:10 -0400159 Browser.saveBookmark(this, name, url);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400160 }
161 break;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800162 default:
163 return super.onContextItemSelected(item);
164 }
165 return true;
166 }
167
168 @Override
169 public void onCreateContextMenu(ContextMenu menu, View v,
170 ContextMenuInfo menuInfo) {
171 AdapterView.AdapterContextMenuInfo i =
172 (AdapterView.AdapterContextMenuInfo) menuInfo;
173
174 MenuInflater inflater = getMenuInflater();
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400175 if (mMostVisited) {
176 inflater.inflate(R.menu.historycontext, menu);
177 } else {
178 inflater.inflate(R.menu.bookmarkscontext, menu);
179 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800180
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400181 if (0 == i.position && !mMostVisited) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800182 menu.setGroupVisible(R.id.CONTEXT_MENU, false);
183 if (mAddHeader == null) {
184 mAddHeader = new AddNewBookmark(BrowserBookmarksPage.this);
185 } else if (mAddHeader.getParent() != null) {
186 ((ViewGroup) mAddHeader.getParent()).
187 removeView(mAddHeader);
188 }
Leon Scroggins892df312009-07-14 14:48:02 -0400189 mAddHeader.setUrl(getIntent().getStringExtra("url"));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800190 menu.setHeaderView(mAddHeader);
191 return;
192 }
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400193 if (mMostVisited) {
Ben Murdoch328ea872009-09-16 13:33:29 +0100194 if ((mViewMode == BookmarkViewMode.LIST
195 && ((HistoryItem) i.targetView).isBookmark())
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400196 || mBookmarksAdapter.getIsBookmark(i.position)) {
197 MenuItem item = menu.findItem(
198 R.id.save_to_bookmarks_menu_id);
199 item.setTitle(R.string.remove_from_bookmarks);
200 }
201 } else {
202 // The historycontext menu has no ADD_MENU group.
203 menu.setGroupVisible(R.id.ADD_MENU, false);
204 }
Leon Scroggins190095d2009-08-17 17:01:38 -0400205 if (mDisableNewWindow) {
Leon Scroggins892df312009-07-14 14:48:02 -0400206 menu.findItem(R.id.new_window_context_menu_id).setVisible(
207 false);
208 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800209 if (mContextHeader == null) {
210 mContextHeader = new BookmarkItem(BrowserBookmarksPage.this);
211 } else if (mContextHeader.getParent() != null) {
212 ((ViewGroup) mContextHeader.getParent()).
213 removeView(mContextHeader);
214 }
Ben Murdoch328ea872009-09-16 13:33:29 +0100215 if (mViewMode == BookmarkViewMode.GRID) {
Leon Scroggins892df312009-07-14 14:48:02 -0400216 mBookmarksAdapter.populateBookmarkItem(mContextHeader,
217 i.position);
218 } else {
219 BookmarkItem b = (BookmarkItem) i.targetView;
220 b.copyTo(mContextHeader);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800221 }
Leon Scroggins892df312009-07-14 14:48:02 -0400222 menu.setHeaderView(mContextHeader);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800223 }
224
225 /**
226 * Create a new BrowserBookmarksPage.
227 */
228 @Override
229 protected void onCreate(Bundle icicle) {
230 super.onCreate(icicle);
231
The Android Open Source Project0c908882009-03-03 19:32:16 -0800232 if (Intent.ACTION_CREATE_SHORTCUT.equals(getIntent().getAction())) {
233 mCreateShortcut = true;
234 }
Leon Scroggins190095d2009-08-17 17:01:38 -0400235 mDisableNewWindow = getIntent().getBooleanExtra("disable_new_window",
236 false);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400237 mMostVisited = getIntent().getBooleanExtra("mostVisited", false);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800238
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400239 if (mCreateShortcut) {
240 setTitle(R.string.browser_bookmarks_page_bookmarks_text);
241 }
Leon Scroggins892df312009-07-14 14:48:02 -0400242 mBookmarksAdapter = new BrowserBookmarksAdapter(this,
Leon Scroggins89c6d362009-07-15 16:54:37 -0400243 getIntent().getStringExtra("url"),
Ben Murdochdcc2b6f2009-09-21 14:29:20 +0100244 getIntent().getStringExtra("title"),
245 (Bitmap) getIntent().getParcelableExtra("thumbnail"),
246 mCreateShortcut,
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400247 mMostVisited);
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400248
249 setContentView(R.layout.empty_history);
250 mEmptyView = findViewById(R.id.empty_view);
251 mEmptyView.setVisibility(View.GONE);
252
Ben Murdoch328ea872009-09-16 13:33:29 +0100253 SharedPreferences p = getPreferences(MODE_PRIVATE);
254
255 // See if the user has set a preference for the view mode of their
256 // bookmarks. Otherwise default to grid mode.
257 BookmarkViewMode preference = BookmarkViewMode.NONE;
258 if (mMostVisited) {
259 preference = BookmarkViewMode.values()[p.getInt(
260 PREF_MOST_VISITED_VIEW_MODE,
261 BookmarkViewMode.GRID.ordinal())];
262 } else {
263 preference = BookmarkViewMode.values()[p.getInt(
264 PREF_BOOKMARK_VIEW_MODE, BookmarkViewMode.GRID.ordinal())];
265 }
266 switchViewMode(preference);
Leon Scroggins892df312009-07-14 14:48:02 -0400267 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800268
Leon Scroggins892df312009-07-14 14:48:02 -0400269 /**
270 * Set the ContentView to be either the grid of thumbnails or the vertical
Ben Murdoch328ea872009-09-16 13:33:29 +0100271 * list.
Leon Scroggins892df312009-07-14 14:48:02 -0400272 */
Ben Murdoch328ea872009-09-16 13:33:29 +0100273 private void switchViewMode(BookmarkViewMode gridMode) {
274 if (mViewMode == gridMode) {
275 return;
276 }
277
278 mViewMode = gridMode;
279
280 // Update the preferences to make the new view mode sticky.
281 Editor ed = getPreferences(MODE_PRIVATE).edit();
282 if (mMostVisited) {
283 ed.putInt(PREF_MOST_VISITED_VIEW_MODE, mViewMode.ordinal());
284 } else {
285 ed.putInt(PREF_BOOKMARK_VIEW_MODE, mViewMode.ordinal());
286 }
287 ed.commit();
288
Leon Scroggins892df312009-07-14 14:48:02 -0400289 mBookmarksAdapter.switchViewMode(gridMode);
Ben Murdoch328ea872009-09-16 13:33:29 +0100290 if (mViewMode == BookmarkViewMode.GRID) {
Leon Scroggins892df312009-07-14 14:48:02 -0400291 if (mGridPage == null) {
Leon Scroggins89c6d362009-07-15 16:54:37 -0400292 mGridPage = new GridView(this);
293 mGridPage.setAdapter(mBookmarksAdapter);
Leon Scroggins892df312009-07-14 14:48:02 -0400294 mGridPage.setOnItemClickListener(mListener);
Leon Scroggins89c6d362009-07-15 16:54:37 -0400295 mGridPage.setNumColumns(GridView.AUTO_FIT);
296 // Keep this in sync with bookmark_thumb and
297 // BrowserActivity.updateScreenshot
298 mGridPage.setColumnWidth(100);
299 mGridPage.setFocusable(true);
300 mGridPage.setFocusableInTouchMode(true);
301 mGridPage.setSelector(android.R.drawable.gallery_thumb);
302 mGridPage.setVerticalSpacing(10);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400303 if (mMostVisited) {
304 mGridPage.setEmptyView(mEmptyView);
305 }
Leon Scroggins892df312009-07-14 14:48:02 -0400306 if (!mCreateShortcut) {
307 mGridPage.setOnCreateContextMenuListener(this);
308 }
309 }
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400310 addContentView(mGridPage, FULL_SCREEN_PARAMS);
311 if (mVerticalList != null) {
312 ViewGroup parent = (ViewGroup) mVerticalList.getParent();
313 if (parent != null) {
314 parent.removeView(mVerticalList);
315 }
316 }
Leon Scroggins892df312009-07-14 14:48:02 -0400317 } else {
318 if (null == mVerticalList) {
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400319 ListView listView = new ListView(this);
Leon Scroggins892df312009-07-14 14:48:02 -0400320 listView.setAdapter(mBookmarksAdapter);
321 listView.setDrawSelectorOnTop(false);
322 listView.setVerticalScrollBarEnabled(true);
323 listView.setOnItemClickListener(mListener);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400324 if (mMostVisited) {
325 listView.setEmptyView(mEmptyView);
326 }
Leon Scroggins892df312009-07-14 14:48:02 -0400327 if (!mCreateShortcut) {
328 listView.setOnCreateContextMenuListener(this);
329 }
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400330 mVerticalList = listView;
Leon Scroggins892df312009-07-14 14:48:02 -0400331 }
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400332 addContentView(mVerticalList, FULL_SCREEN_PARAMS);
333 if (mGridPage != null) {
334 ViewGroup parent = (ViewGroup) mGridPage.getParent();
335 if (parent != null) {
336 parent.removeView(mGridPage);
337 }
338 }
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400339 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800340 }
341
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400342 private static final ViewGroup.LayoutParams FULL_SCREEN_PARAMS
343 = new ViewGroup.LayoutParams(
344 ViewGroup.LayoutParams.FILL_PARENT,
345 ViewGroup.LayoutParams.FILL_PARENT);
346
The Android Open Source Project0c908882009-03-03 19:32:16 -0800347 private static final int SAVE_CURRENT_PAGE = 1000;
348 private final Handler mHandler = new Handler() {
349 @Override
350 public void handleMessage(Message msg) {
351 if (msg.what == SAVE_CURRENT_PAGE) {
352 saveCurrentPage();
353 }
354 }
355 };
356
357 private AdapterView.OnItemClickListener mListener = new AdapterView.OnItemClickListener() {
358 public void onItemClick(AdapterView parent, View v, int position, long id) {
359 // It is possible that the view has been canceled when we get to
360 // this point as back has a higher priority
361 if (mCanceled) {
Leon Scroggins892df312009-07-14 14:48:02 -0400362 android.util.Log.e(LOGTAG, "item clicked when dismissing");
The Android Open Source Project0c908882009-03-03 19:32:16 -0800363 return;
364 }
365 if (!mCreateShortcut) {
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400366 if (0 == position && !mMostVisited) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800367 // XXX: Work-around for a framework issue.
368 mHandler.sendEmptyMessage(SAVE_CURRENT_PAGE);
369 } else {
370 loadUrl(position);
371 }
372 } else {
Patrick Scott3918d442009-08-04 13:22:29 -0400373 final Intent intent = createShortcutIntent(position);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800374 setResultToParent(RESULT_OK, intent);
375 finish();
376 }
377 }
378 };
379
Patrick Scott3918d442009-08-04 13:22:29 -0400380 private Intent createShortcutIntent(int position) {
381 String url = getUrl(position);
382 String title = getBookmarkTitle(position);
383 Bitmap touchIcon = getTouchIcon(position);
384
The Android Open Source Project0c908882009-03-03 19:32:16 -0800385 final Intent i = new Intent();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700386 final Intent shortcutIntent = new Intent(Intent.ACTION_VIEW,
387 Uri.parse(url));
388 long urlHash = url.hashCode();
389 long uniqueId = (urlHash << 32) | shortcutIntent.hashCode();
390 shortcutIntent.putExtra(Browser.EXTRA_APPLICATION_ID,
391 Long.toString(uniqueId));
392 i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800393 i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
Patrick Scott3918d442009-08-04 13:22:29 -0400394 // Use the apple-touch-icon if available
395 if (touchIcon != null) {
396 // Make a copy so we can modify the pixels.
397 Bitmap copy = touchIcon.copy(Bitmap.Config.ARGB_8888, true);
Patrick Scotte09761e2009-03-24 20:43:37 -0700398 Canvas canvas = new Canvas(copy);
399
Patrick Scott3918d442009-08-04 13:22:29 -0400400 // Construct a path from a round rect. This will allow drawing with
401 // an inverse fill so we can punch a hole using the round rect.
402 Path path = new Path();
403 path.setFillType(Path.FillType.INVERSE_WINDING);
Patrick Scott59ce8302009-09-18 16:29:38 -0400404 RectF rect = new RectF(0, 0, touchIcon.getWidth(),
405 touchIcon.getHeight());
406 rect.inset(1, 1);
407 path.addRoundRect(rect, 8f, 8f, Path.Direction.CW);
Patrick Scotte09761e2009-03-24 20:43:37 -0700408
Patrick Scott3918d442009-08-04 13:22:29 -0400409 // Construct a paint that clears the outside of the rectangle and
410 // draw.
411 Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
412 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
413 canvas.drawPath(path, paint);
Patrick Scotte09761e2009-03-24 20:43:37 -0700414
Patrick Scotte09761e2009-03-24 20:43:37 -0700415 i.putExtra(Intent.EXTRA_SHORTCUT_ICON, copy);
Patrick Scott3918d442009-08-04 13:22:29 -0400416 } else {
417 Bitmap favicon = getFavicon(position);
418 if (favicon == null) {
419 i.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
420 Intent.ShortcutIconResource.fromContext(
421 BrowserBookmarksPage.this,
422 R.drawable.ic_launcher_shortcut_browser_bookmark));
423 } else {
424 Bitmap icon = BitmapFactory.decodeResource(getResources(),
425 R.drawable.ic_launcher_shortcut_browser_bookmark);
426
427 // Make a copy of the regular icon so we can modify the pixels.
428 Bitmap copy = icon.copy(Bitmap.Config.ARGB_8888, true);
429 Canvas canvas = new Canvas(copy);
430
431 // Make a Paint for the white background rectangle and for
432 // filtering the favicon.
433 Paint p = new Paint(Paint.ANTI_ALIAS_FLAG
434 | Paint.FILTER_BITMAP_FLAG);
435 p.setStyle(Paint.Style.FILL_AND_STROKE);
436 p.setColor(Color.WHITE);
437
438 // Create a rectangle that is slightly wider than the favicon
439 final float iconSize = 16; // 16x16 favicon
440 final float padding = 2; // white padding around icon
441 final float rectSize = iconSize + 2 * padding;
442 final float y = icon.getHeight() - rectSize;
443 RectF r = new RectF(0, y, rectSize, y + rectSize);
444
445 // Draw a white rounded rectangle behind the favicon
446 canvas.drawRoundRect(r, 2, 2, p);
447
448 // Draw the favicon in the same rectangle as the rounded
449 // rectangle but inset by the padding
450 // (results in a 16x16 favicon).
451 r.inset(padding, padding);
452 canvas.drawBitmap(favicon, null, r, p);
453 i.putExtra(Intent.EXTRA_SHORTCUT_ICON, copy);
454 }
Patrick Scotte09761e2009-03-24 20:43:37 -0700455 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800456 // Do not allow duplicate items
457 i.putExtra("duplicate", false);
458 return i;
459 }
460
461 private void saveCurrentPage() {
462 Intent i = new Intent(BrowserBookmarksPage.this,
463 AddBookmarkPage.class);
464 i.putExtras(getIntent());
465 startActivityForResult(i, BOOKMARKS_SAVE);
466 }
467
468 private void loadUrl(int position) {
469 Intent intent = (new Intent()).setAction(getUrl(position));
470 setResultToParent(RESULT_OK, intent);
471 finish();
472 }
473
474 @Override
475 public boolean onCreateOptionsMenu(Menu menu) {
476 boolean result = super.onCreateOptionsMenu(menu);
477 if (!mCreateShortcut) {
478 MenuInflater inflater = getMenuInflater();
479 inflater.inflate(R.menu.bookmarks, menu);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400480 // Most visited page does not have an option to bookmark the last
481 // viewed page.
482 menu.findItem(R.id.new_context_menu_id).setVisible(!mMostVisited);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800483 return true;
484 }
485 return result;
486 }
487
488 @Override
Leon Scroggins0c786502009-08-04 16:04:55 -0400489 public boolean onPrepareOptionsMenu(Menu menu) {
Leon Scroggins8382d992009-08-19 11:25:14 -0400490 boolean result = super.onPrepareOptionsMenu(menu);
491 if (mCreateShortcut || mBookmarksAdapter.getCount() == 0) {
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400492 // No need to show the menu if there are no items.
Leon Scroggins8382d992009-08-19 11:25:14 -0400493 return result;
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400494 }
Leon Scroggins0c786502009-08-04 16:04:55 -0400495 menu.findItem(R.id.switch_mode_menu_id).setTitle(
Ben Murdoch328ea872009-09-16 13:33:29 +0100496 mViewMode == BookmarkViewMode.GRID ? R.string.switch_to_list
Leon Scroggins0c786502009-08-04 16:04:55 -0400497 : R.string.switch_to_thumbnails);
498 return true;
499 }
500
501 @Override
The Android Open Source Project0c908882009-03-03 19:32:16 -0800502 public boolean onOptionsItemSelected(MenuItem item) {
503 switch (item.getItemId()) {
Leon Scroggins892df312009-07-14 14:48:02 -0400504 case R.id.new_context_menu_id:
505 saveCurrentPage();
506 break;
507
508 case R.id.switch_mode_menu_id:
Ben Murdoch328ea872009-09-16 13:33:29 +0100509 if (mViewMode == BookmarkViewMode.GRID) {
510 switchViewMode(BookmarkViewMode.LIST);
511 } else {
512 switchViewMode(BookmarkViewMode.GRID);
513 }
Leon Scroggins892df312009-07-14 14:48:02 -0400514 break;
515
516 default:
517 return super.onOptionsItemSelected(item);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800518 }
519 return true;
520 }
521
522 private void openInNewWindow(int position) {
523 Bundle b = new Bundle();
524 b.putBoolean("new_window", true);
525 setResultToParent(RESULT_OK,
526 (new Intent()).setAction(getUrl(position)).putExtras(b));
527
528 finish();
529 }
530
531
532 private void editBookmark(int position) {
533 Intent intent = new Intent(BrowserBookmarksPage.this,
534 AddBookmarkPage.class);
535 intent.putExtra("bookmark", getRow(position));
536 startActivityForResult(intent, BOOKMARKS_SAVE);
537 }
538
539 @Override
540 protected void onActivityResult(int requestCode, int resultCode,
541 Intent data) {
542 switch(requestCode) {
543 case BOOKMARKS_SAVE:
544 if (resultCode == RESULT_OK) {
545 Bundle extras;
546 if (data != null && (extras = data.getExtras()) != null) {
547 // If there are extras, then we need to save
548 // the edited bookmark. This is done in updateRow()
549 String title = extras.getString("title");
550 String url = extras.getString("url");
551 if (title != null && url != null) {
552 mBookmarksAdapter.updateRow(extras);
553 }
554 } else {
555 // extras == null then a new bookmark was added to
556 // the database.
557 refreshList();
558 }
559 }
560 break;
561 default:
562 break;
563 }
564 }
565
566 private void displayRemoveBookmarkDialog(int position) {
567 // Put up a dialog asking if the user really wants to
568 // delete the bookmark
569 final int deletePos = position;
570 new AlertDialog.Builder(this)
571 .setTitle(R.string.delete_bookmark)
572 .setIcon(android.R.drawable.ic_dialog_alert)
573 .setMessage(getText(R.string.delete_bookmark_warning).toString().replace(
574 "%s", getBookmarkTitle(deletePos)))
575 .setPositiveButton(R.string.ok,
576 new DialogInterface.OnClickListener() {
577 public void onClick(DialogInterface dialog, int whichButton) {
578 deleteBookmark(deletePos);
579 }
580 })
581 .setNegativeButton(R.string.cancel, null)
582 .show();
583 }
584
585 /**
586 * Refresh the shown list after the database has changed.
587 */
Leon Scroggins892df312009-07-14 14:48:02 -0400588 private void refreshList() {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800589 mBookmarksAdapter.refreshList();
590 }
591
592 /**
593 * Return a hashmap representing the currently highlighted row.
594 */
595 public Bundle getRow(int position) {
596 return mBookmarksAdapter.getRow(position);
597 }
598
599 /**
600 * Return the url of the currently highlighted row.
601 */
602 public String getUrl(int position) {
603 return mBookmarksAdapter.getUrl(position);
604 }
605
Patrick Scotte09761e2009-03-24 20:43:37 -0700606 /**
607 * Return the favicon of the currently highlighted row.
608 */
609 public Bitmap getFavicon(int position) {
610 return mBookmarksAdapter.getFavicon(position);
611 }
612
Patrick Scott3918d442009-08-04 13:22:29 -0400613 private Bitmap getTouchIcon(int position) {
614 return mBookmarksAdapter.getTouchIcon(position);
615 }
616
The Android Open Source Project0c908882009-03-03 19:32:16 -0800617 private void copy(CharSequence text) {
618 try {
619 IClipboard clip = IClipboard.Stub.asInterface(ServiceManager.getService("clipboard"));
620 if (clip != null) {
621 clip.setClipboardText(text);
622 }
623 } catch (android.os.RemoteException e) {
624 Log.e(LOGTAG, "Copy failed", e);
625 }
626 }
627
628 public String getBookmarkTitle(int position) {
629 return mBookmarksAdapter.getTitle(position);
630 }
631
632 /**
633 * Delete the currently highlighted row.
634 */
635 public void deleteBookmark(int position) {
636 mBookmarksAdapter.deleteRow(position);
637 }
Grace Kloba5942df02009-09-18 11:48:29 -0700638
639 @Override
640 public void onBackPressed() {
641 setResultToParent(RESULT_CANCELED, null);
642 mCanceled = true;
643 super.onBackPressed();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800644 }
645
646 // This Activity is generally a sub-Activity of CombinedHistoryActivity. In
647 // that situation, we need to pass our result code up to our parent.
648 // However, if someone calls this Activity directly, then this has no
649 // parent, and it needs to set it on itself.
650 private void setResultToParent(int resultCode, Intent data) {
651 Activity a = getParent() == null ? this : getParent();
652 a.setResult(resultCode, data);
653 }
654}