OSDN Git Service

Use new assets for list view and thumbnail view.
[android-x86/packages-apps-Browser.git] / src / com / android / browser / BrowserBookmarksPage.java
1 /*
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
17 package com.android.browser;
18
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.content.DialogInterface;
22 import android.content.Intent;
23 import android.content.SharedPreferences;
24 import android.content.SharedPreferences.Editor;
25 import android.graphics.Bitmap;
26 import android.graphics.BitmapFactory;
27 import android.graphics.Canvas;
28 import android.graphics.Color;
29 import android.graphics.Paint;
30 import android.graphics.Path;
31 import android.graphics.PorterDuff;
32 import android.graphics.PorterDuffXfermode;
33 import android.graphics.RectF;
34 import android.net.Uri;
35 import android.os.Bundle;
36 import android.os.Handler;
37 import android.os.Message;
38 import android.os.ServiceManager;
39 import android.provider.Browser;
40 import android.text.IClipboard;
41 import android.util.Log;
42 import android.view.ContextMenu;
43 import android.view.KeyEvent;
44 import android.view.LayoutInflater;
45 import android.view.Menu;
46 import android.view.MenuInflater;
47 import android.view.MenuItem;
48 import android.view.View;
49 import android.view.ViewGroup;
50 import android.view.ViewGroup.LayoutParams;
51 import android.view.ViewStub;
52 import android.view.ContextMenu.ContextMenuInfo;
53 import android.widget.AdapterView;
54 import android.widget.GridView;
55 import android.widget.ListView;
56 import android.widget.Toast;
57
58 /*package*/ enum BookmarkViewMode { NONE, GRID, LIST }
59 /**
60  *  View showing the user's bookmarks in the browser.
61  */
62 public class BrowserBookmarksPage extends Activity implements 
63         View.OnCreateContextMenuListener {
64
65     private BookmarkViewMode        mViewMode = BookmarkViewMode.NONE;
66     private GridView                mGridPage;
67     private View                    mVerticalList;
68     private BrowserBookmarksAdapter mBookmarksAdapter;
69     private static final int        BOOKMARKS_SAVE = 1;
70     private boolean                 mDisableNewWindow;
71     private BookmarkItem            mContextHeader;
72     private AddNewBookmark          mAddHeader;
73     private boolean                 mCanceled = false;
74     private boolean                 mCreateShortcut;
75     private boolean                 mMostVisited;
76     private View                    mEmptyView;
77     // 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";
83     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";
85
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:
111             final Intent send = createShortcutIntent(i.position);
112             send.setAction(INSTALL_SHORTCUT);
113             sendBroadcast(send);
114             break;
115         case R.id.delete_context_menu_id:
116             if (mMostVisited) {
117                 Browser.deleteFromHistory(getContentResolver(),
118                         getUrl(i.position));
119                 refreshList();
120             } else {
121                 displayRemoveBookmarkDialog(i.position);
122             }
123             break;
124         case R.id.new_window_context_menu_id:
125             openInNewWindow(i.position);
126             break;
127         case R.id.share_link_context_menu_id:
128             Browser.sendString(BrowserBookmarksPage.this, getUrl(i.position),
129                     getText(R.string.choosertitle_sharevia).toString());
130             break;
131         case R.id.copy_url_context_menu_id:
132             copy(getUrl(i.position));
133             break;
134         case R.id.homepage_context_menu_id:
135             BrowserSettings.getInstance().setHomePage(this,
136                     getUrl(i.position));
137             Toast.makeText(this, R.string.homepage_set,
138                     Toast.LENGTH_LONG).show();
139             break;
140         // Only for the Most visited page
141         case R.id.save_to_bookmarks_menu_id:
142             boolean isBookmark;
143             String name;
144             String url;
145             if (mViewMode == BookmarkViewMode.GRID) {
146                 isBookmark = mBookmarksAdapter.getIsBookmark(i.position);
147                 name = mBookmarksAdapter.getTitle(i.position);
148                 url = mBookmarksAdapter.getUrl(i.position);
149             } else {
150                 HistoryItem historyItem = ((HistoryItem) i.targetView);
151                 isBookmark = historyItem.isBookmark();
152                 name = historyItem.getName();
153                 url = historyItem.getUrl();
154             }
155             // If the site is bookmarked, the item becomes remove from
156             // bookmarks.
157             if (isBookmark) {
158                 Bookmarks.removeFromBookmarks(this, getContentResolver(), url, name);
159             } else {
160                 Browser.saveBookmark(this, name, url);
161             }
162             break;
163         default:
164             return super.onContextItemSelected(item);
165         }
166         return true;
167     }
168
169     @Override
170     public void onCreateContextMenu(ContextMenu menu, View v,
171                 ContextMenuInfo menuInfo) {
172             AdapterView.AdapterContextMenuInfo i = 
173                     (AdapterView.AdapterContextMenuInfo) menuInfo;
174
175             MenuInflater inflater = getMenuInflater();
176             if (mMostVisited) {
177                 inflater.inflate(R.menu.historycontext, menu);
178             } else {
179                 inflater.inflate(R.menu.bookmarkscontext, menu);
180             }
181
182             if (0 == i.position && !mMostVisited) {
183                 menu.setGroupVisible(R.id.CONTEXT_MENU, false);
184                 if (mAddHeader == null) {
185                     mAddHeader = new AddNewBookmark(BrowserBookmarksPage.this);
186                 } else if (mAddHeader.getParent() != null) {
187                     ((ViewGroup) mAddHeader.getParent()).
188                             removeView(mAddHeader);
189                 }
190                 mAddHeader.setUrl(getIntent().getStringExtra("url"));
191                 menu.setHeaderView(mAddHeader);
192                 return;
193             }
194             if (mMostVisited) {
195                 if ((mViewMode == BookmarkViewMode.LIST
196                         && ((HistoryItem) i.targetView).isBookmark())
197                         || mBookmarksAdapter.getIsBookmark(i.position)) {
198                     MenuItem item = menu.findItem(
199                             R.id.save_to_bookmarks_menu_id);
200                     item.setTitle(R.string.remove_from_bookmarks);
201                 }
202             } else {
203                 // The historycontext menu has no ADD_MENU group.
204                 menu.setGroupVisible(R.id.ADD_MENU, false);
205             }
206             if (mDisableNewWindow) {
207                 menu.findItem(R.id.new_window_context_menu_id).setVisible(
208                         false);
209             }
210             if (mContextHeader == null) {
211                 mContextHeader = new BookmarkItem(BrowserBookmarksPage.this);
212             } else if (mContextHeader.getParent() != null) {
213                 ((ViewGroup) mContextHeader.getParent()).
214                         removeView(mContextHeader);
215             }
216             if (mViewMode == BookmarkViewMode.GRID) {
217                 mBookmarksAdapter.populateBookmarkItem(mContextHeader,
218                         i.position);
219             } else {
220                 BookmarkItem b = (BookmarkItem) i.targetView;
221                 b.copyTo(mContextHeader);
222             }
223             menu.setHeaderView(mContextHeader);
224         }
225
226     /**
227      *  Create a new BrowserBookmarksPage.
228      */  
229     @Override
230     protected void onCreate(Bundle icicle) {
231         super.onCreate(icicle);
232
233         if (Intent.ACTION_CREATE_SHORTCUT.equals(getIntent().getAction())) {
234             mCreateShortcut = true;
235         }
236         mDisableNewWindow = getIntent().getBooleanExtra("disable_new_window",
237                 false);
238         mMostVisited = getIntent().getBooleanExtra("mostVisited", false);
239
240         if (mCreateShortcut) {
241             setTitle(R.string.browser_bookmarks_page_bookmarks_text);
242         }
243         mBookmarksAdapter = new BrowserBookmarksAdapter(this,
244                         getIntent().getStringExtra("url"),
245                         getIntent().getStringExtra("title"),
246                         (Bitmap) getIntent().getParcelableExtra("thumbnail"),
247                         mCreateShortcut,
248                         mMostVisited);
249
250         setContentView(R.layout.empty_history);
251         mEmptyView = findViewById(R.id.empty_view);
252         mEmptyView.setVisibility(View.GONE);
253
254         SharedPreferences p = getPreferences(MODE_PRIVATE);
255
256         // See if the user has set a preference for the view mode of their
257         // bookmarks. Otherwise default to grid mode.
258         BookmarkViewMode preference = BookmarkViewMode.NONE;
259         if (mMostVisited) {
260             preference = BookmarkViewMode.values()[p.getInt(
261                     PREF_MOST_VISITED_VIEW_MODE,
262                     BookmarkViewMode.GRID.ordinal())];
263         } else {
264             preference = BookmarkViewMode.values()[p.getInt(
265                     PREF_BOOKMARK_VIEW_MODE, BookmarkViewMode.GRID.ordinal())];
266         }
267         switchViewMode(preference);
268     }
269
270     /**
271      *  Set the ContentView to be either the grid of thumbnails or the vertical
272      *  list.
273      */
274     private void switchViewMode(BookmarkViewMode gridMode) {
275         if (mViewMode == gridMode) {
276             return;
277         }
278
279         mViewMode = gridMode;
280
281         // Update the preferences to make the new view mode sticky.
282         Editor ed = getPreferences(MODE_PRIVATE).edit();
283         if (mMostVisited) {
284             ed.putInt(PREF_MOST_VISITED_VIEW_MODE, mViewMode.ordinal());
285         } else {
286             ed.putInt(PREF_BOOKMARK_VIEW_MODE, mViewMode.ordinal());
287         }
288         ed.commit();
289
290         mBookmarksAdapter.switchViewMode(gridMode);
291         if (mViewMode == BookmarkViewMode.GRID) {
292             if (mGridPage == null) {
293                 mGridPage = new GridView(this);
294                 mGridPage.setAdapter(mBookmarksAdapter);
295                 mGridPage.setOnItemClickListener(mListener);
296                 mGridPage.setNumColumns(GridView.AUTO_FIT);
297                 mGridPage.setColumnWidth(
298                         BrowserActivity.getDesiredThumbnailWidth(this));
299                 mGridPage.setFocusable(true);
300                 mGridPage.setFocusableInTouchMode(true);
301                 mGridPage.setSelector(android.R.drawable.gallery_thumb);
302                 float density = getResources().getDisplayMetrics().density;
303                 mGridPage.setVerticalSpacing((int) (14 * density));
304                 mGridPage.setHorizontalSpacing((int) (8 * density));
305                 mGridPage.setStretchMode(GridView.STRETCH_SPACING);
306                 mGridPage.setDrawSelectorOnTop(true);
307                 if (mMostVisited) {
308                     mGridPage.setEmptyView(mEmptyView);
309                 }
310                 if (!mCreateShortcut) {
311                     mGridPage.setOnCreateContextMenuListener(this);
312                 }
313             }
314             addContentView(mGridPage, FULL_SCREEN_PARAMS);
315             if (mVerticalList != null) {
316                 ViewGroup parent = (ViewGroup) mVerticalList.getParent();
317                 if (parent != null) {
318                     parent.removeView(mVerticalList);
319                 }
320             }
321         } else {
322             if (null == mVerticalList) {
323                 ListView listView = new ListView(this);
324                 listView.setAdapter(mBookmarksAdapter);
325                 listView.setDrawSelectorOnTop(false);
326                 listView.setVerticalScrollBarEnabled(true);
327                 listView.setOnItemClickListener(mListener);
328                 if (mMostVisited) {
329                     listView.setEmptyView(mEmptyView);
330                 }
331                 if (!mCreateShortcut) {
332                     listView.setOnCreateContextMenuListener(this);
333                 }
334                 mVerticalList = listView;
335             }
336             addContentView(mVerticalList, FULL_SCREEN_PARAMS);
337             if (mGridPage != null) {
338                 ViewGroup parent = (ViewGroup) mGridPage.getParent();
339                 if (parent != null) {
340                     parent.removeView(mGridPage);
341                 }
342             }
343         }
344     }
345
346     private static final ViewGroup.LayoutParams FULL_SCREEN_PARAMS
347             = new ViewGroup.LayoutParams(
348             ViewGroup.LayoutParams.FILL_PARENT,
349             ViewGroup.LayoutParams.FILL_PARENT);
350
351     private static final int SAVE_CURRENT_PAGE = 1000;
352     private final Handler mHandler = new Handler() {
353         @Override
354         public void handleMessage(Message msg) {
355             if (msg.what == SAVE_CURRENT_PAGE) {
356                 saveCurrentPage();
357             }
358         }
359     };
360
361     private AdapterView.OnItemClickListener mListener = new AdapterView.OnItemClickListener() {
362         public void onItemClick(AdapterView parent, View v, int position, long id) {
363             // It is possible that the view has been canceled when we get to
364             // this point as back has a higher priority 
365             if (mCanceled) {
366                 android.util.Log.e(LOGTAG, "item clicked when dismissing");
367                 return;
368             }
369             if (!mCreateShortcut) {
370                 if (0 == position && !mMostVisited) {
371                     // XXX: Work-around for a framework issue.
372                     mHandler.sendEmptyMessage(SAVE_CURRENT_PAGE);
373                 } else {
374                     loadUrl(position);
375                 }
376             } else {
377                 final Intent intent = createShortcutIntent(position);
378                 setResultToParent(RESULT_OK, intent);
379                 finish();
380             }
381         }
382     };
383
384     private Intent createShortcutIntent(int position) {
385         String url = getUrl(position);
386         String title = getBookmarkTitle(position);
387         Bitmap touchIcon = getTouchIcon(position);
388
389         final Intent i = new Intent();
390         final Intent shortcutIntent = new Intent(Intent.ACTION_VIEW,
391                 Uri.parse(url));
392         long urlHash = url.hashCode();
393         long uniqueId = (urlHash << 32) | shortcutIntent.hashCode();
394         shortcutIntent.putExtra(Browser.EXTRA_APPLICATION_ID,
395                 Long.toString(uniqueId));
396         i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
397         i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
398         // Use the apple-touch-icon if available
399         if (touchIcon != null) {
400             // Make a copy so we can modify the pixels.
401             Bitmap copy = touchIcon.copy(Bitmap.Config.ARGB_8888, true);
402             Canvas canvas = new Canvas(copy);
403
404             // Construct a path from a round rect. This will allow drawing with
405             // an inverse fill so we can punch a hole using the round rect.
406             Path path = new Path();
407             path.setFillType(Path.FillType.INVERSE_WINDING);
408             RectF rect = new RectF(0, 0, touchIcon.getWidth(),
409                     touchIcon.getHeight());
410             rect.inset(1, 1);
411             path.addRoundRect(rect, 8f, 8f, Path.Direction.CW);
412
413             // Construct a paint that clears the outside of the rectangle and
414             // draw.
415             Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
416             paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
417             canvas.drawPath(path, paint);
418
419             i.putExtra(Intent.EXTRA_SHORTCUT_ICON, copy);
420         } else {
421             Bitmap favicon = getFavicon(position);
422             if (favicon == null) {
423                 i.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
424                         Intent.ShortcutIconResource.fromContext(
425                                 BrowserBookmarksPage.this,
426                                 R.drawable.ic_launcher_shortcut_browser_bookmark));
427             } else {
428                 Bitmap icon = BitmapFactory.decodeResource(getResources(),
429                         R.drawable.ic_launcher_shortcut_browser_bookmark);
430
431                 // Make a copy of the regular icon so we can modify the pixels.
432                 Bitmap copy = icon.copy(Bitmap.Config.ARGB_8888, true);
433                 Canvas canvas = new Canvas(copy);
434
435                 // Make a Paint for the white background rectangle and for
436                 // filtering the favicon.
437                 Paint p = new Paint(Paint.ANTI_ALIAS_FLAG
438                         | Paint.FILTER_BITMAP_FLAG);
439                 p.setStyle(Paint.Style.FILL_AND_STROKE);
440                 p.setColor(Color.WHITE);
441
442                 // Create a rectangle that is slightly wider than the favicon
443                 final float iconSize = 16; // 16x16 favicon
444                 final float padding = 2;   // white padding around icon
445                 final float rectSize = iconSize + 2 * padding;
446                 final float y = icon.getHeight() - rectSize;
447                 RectF r = new RectF(0, y, rectSize, y + rectSize);
448
449                 // Draw a white rounded rectangle behind the favicon
450                 canvas.drawRoundRect(r, 2, 2, p);
451
452                 // Draw the favicon in the same rectangle as the rounded
453                 // rectangle but inset by the padding
454                 // (results in a 16x16 favicon).
455                 r.inset(padding, padding);
456                 canvas.drawBitmap(favicon, null, r, p);
457                 i.putExtra(Intent.EXTRA_SHORTCUT_ICON, copy);
458             }
459         }
460         // Do not allow duplicate items
461         i.putExtra("duplicate", false);
462         return i;
463     }
464
465     private void saveCurrentPage() {
466         Intent i = new Intent(BrowserBookmarksPage.this,
467                 AddBookmarkPage.class);
468         i.putExtras(getIntent());
469         startActivityForResult(i, BOOKMARKS_SAVE);
470     }
471
472     private void loadUrl(int position) {
473         Intent intent = (new Intent()).setAction(getUrl(position));
474         setResultToParent(RESULT_OK, intent);
475         finish();
476     }
477
478     @Override
479     public boolean onCreateOptionsMenu(Menu menu) {
480         boolean result = super.onCreateOptionsMenu(menu);
481         if (!mCreateShortcut) {
482             MenuInflater inflater = getMenuInflater();
483             inflater.inflate(R.menu.bookmarks, menu);
484             // Most visited page does not have an option to bookmark the last
485             // viewed page.
486             menu.findItem(R.id.new_context_menu_id).setVisible(!mMostVisited);
487             return true;
488         }
489         return result;
490     }
491
492     @Override
493     public boolean onPrepareOptionsMenu(Menu menu) {
494         boolean result = super.onPrepareOptionsMenu(menu);
495         if (mCreateShortcut || mBookmarksAdapter.getCount() == 0) {
496             // No need to show the menu if there are no items.
497             return result;
498         }
499         MenuItem switchItem = menu.findItem(R.id.switch_mode_menu_id);
500         int titleResId;
501         int iconResId;
502         if (mViewMode == BookmarkViewMode.GRID) {
503             titleResId = R.string.switch_to_list;
504             iconResId = R.drawable.ic_menu_list;
505         } else {
506             titleResId = R.string.switch_to_thumbnails;
507             iconResId = R.drawable.ic_menu_thumbnail;
508         }
509         switchItem.setTitle(titleResId);
510         switchItem.setIcon(iconResId);
511         return true;
512     }
513
514     @Override
515     public boolean onOptionsItemSelected(MenuItem item) {
516         switch (item.getItemId()) {
517         case R.id.new_context_menu_id:
518             saveCurrentPage();
519             break;
520
521         case R.id.switch_mode_menu_id:
522             if (mViewMode == BookmarkViewMode.GRID) {
523                 switchViewMode(BookmarkViewMode.LIST);
524             } else {
525                 switchViewMode(BookmarkViewMode.GRID);
526             }
527             break;
528
529         default:
530             return super.onOptionsItemSelected(item);
531         }
532         return true;
533     }
534
535     private void openInNewWindow(int position) {
536         Bundle b = new Bundle();
537         b.putBoolean("new_window", true);
538         setResultToParent(RESULT_OK,
539                 (new Intent()).setAction(getUrl(position)).putExtras(b));
540
541         finish();
542     }
543     
544
545     private void editBookmark(int position) {
546         Intent intent = new Intent(BrowserBookmarksPage.this, 
547             AddBookmarkPage.class);
548         intent.putExtra("bookmark", getRow(position));
549         startActivityForResult(intent, BOOKMARKS_SAVE);
550     }
551
552     @Override
553     protected void onActivityResult(int requestCode, int resultCode,
554                                     Intent data) {
555         switch(requestCode) {
556             case BOOKMARKS_SAVE:
557                 if (resultCode == RESULT_OK) {
558                     Bundle extras;
559                     if (data != null && (extras = data.getExtras()) != null) {
560                         // If there are extras, then we need to save
561                         // the edited bookmark. This is done in updateRow()
562                         String title = extras.getString("title");
563                         String url = extras.getString("url");
564                         if (title != null && url != null) {
565                             mBookmarksAdapter.updateRow(extras);
566                         }
567                     } else {
568                         // extras == null then a new bookmark was added to
569                         // the database.
570                         refreshList();
571                     }
572                 }
573                 break;
574             default:
575                 break;
576         }
577     }
578     
579     private void displayRemoveBookmarkDialog(int position) {
580         // Put up a dialog asking if the user really wants to
581         // delete the bookmark
582         final int deletePos = position;
583         new AlertDialog.Builder(this)
584                 .setTitle(R.string.delete_bookmark)
585                 .setIcon(android.R.drawable.ic_dialog_alert)
586                 .setMessage(getText(R.string.delete_bookmark_warning).toString().replace(
587                         "%s", getBookmarkTitle(deletePos)))
588                 .setPositiveButton(R.string.ok, 
589                         new DialogInterface.OnClickListener() {
590                             public void onClick(DialogInterface dialog, int whichButton) {
591                                 deleteBookmark(deletePos);
592                             }
593                         })
594                 .setNegativeButton(R.string.cancel, null)
595                 .show();
596     }
597
598     /**
599      *  Refresh the shown list after the database has changed.
600      */
601     private void refreshList() {
602         mBookmarksAdapter.refreshList();
603     }
604     
605     /**
606      *  Return a hashmap representing the currently highlighted row.
607      */
608     public Bundle getRow(int position) {
609         return mBookmarksAdapter.getRow(position);
610     }
611
612     /**
613      *  Return the url of the currently highlighted row.
614      */
615     public String getUrl(int position) {
616         return mBookmarksAdapter.getUrl(position);
617     }
618
619     /**
620      * Return the favicon of the currently highlighted row.
621      */
622     public Bitmap getFavicon(int position) {
623         return mBookmarksAdapter.getFavicon(position);
624     }
625
626     private Bitmap getTouchIcon(int position) {
627         return mBookmarksAdapter.getTouchIcon(position);
628     }
629
630     private void copy(CharSequence text) {
631         try {
632             IClipboard clip = IClipboard.Stub.asInterface(ServiceManager.getService("clipboard"));
633             if (clip != null) {
634                 clip.setClipboardText(text);
635             }
636         } catch (android.os.RemoteException e) {
637             Log.e(LOGTAG, "Copy failed", e);
638         }
639     }
640     
641     public String getBookmarkTitle(int position) {
642         return mBookmarksAdapter.getTitle(position);
643     }
644
645     /**
646      *  Delete the currently highlighted row.
647      */
648     public void deleteBookmark(int position) {
649         mBookmarksAdapter.deleteRow(position);
650     }
651
652     @Override
653     public void onBackPressed() {
654         setResultToParent(RESULT_CANCELED, null);
655         mCanceled = true;
656         super.onBackPressed();
657     }
658
659     // This Activity is generally a sub-Activity of CombinedHistoryActivity. In
660     // that situation, we need to pass our result code up to our parent.
661     // However, if someone calls this Activity directly, then this has no
662     // parent, and it needs to set it on itself.
663     private void setResultToParent(int resultCode, Intent data) {
664         Activity a = getParent() == null ? this : getParent();
665         a.setResult(resultCode, data);
666     }
667 }