blob: 580723cce4395d2a13eb82a88681ee41dd7fb3c7 [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;
luxiaoldbe4a622013-07-19 17:14:06 +080020import android.app.AlertDialog;
Leon Scroggins III052ce662010-09-13 14:44:16 -040021import android.app.LoaderManager;
John Reck2eec4c32011-05-11 15:55:32 -070022import android.app.LoaderManager.LoaderCallbacks;
23import android.content.AsyncTaskLoader;
The Android Open Source Project0c908882009-03-03 19:32:16 -080024import android.content.ContentResolver;
Michael Kolbd40ac1a2010-09-29 00:23:46 -070025import android.content.ContentUris;
Leon Scroggins III052ce662010-09-13 14:44:16 -040026import android.content.ContentValues;
27import android.content.Context;
28import android.content.CursorLoader;
luxiaoldbe4a622013-07-19 17:14:06 +080029import android.content.DialogInterface;
Leon Scroggins III052ce662010-09-13 14:44:16 -040030import android.content.Loader;
The Android Open Source Project0c908882009-03-03 19:32:16 -080031import android.content.res.Resources;
Patrick Scott3918d442009-08-04 13:22:29 -040032import android.database.Cursor;
Ben Murdochaac7aa62009-09-17 16:57:40 +010033import android.graphics.Bitmap;
Leon Scroggins02081942010-11-01 17:52:42 -040034import android.graphics.drawable.Drawable;
The Android Open Source Project0c908882009-03-03 19:32:16 -080035import android.net.ParseException;
Michael Kolbd40ac1a2010-09-29 00:23:46 -070036import android.net.Uri;
The Android Open Source Project0c908882009-03-03 19:32:16 -080037import android.net.WebAddress;
John Reckc8490812010-11-22 14:15:36 -080038import android.os.AsyncTask;
The Android Open Source Project0c908882009-03-03 19:32:16 -080039import android.os.Bundle;
Ben Murdoch1794fe22009-09-29 18:14:30 +010040import android.os.Handler;
41import android.os.Message;
luxiaoldbe4a622013-07-19 17:14:06 +080042import android.provider.Browser;
Leon Scroggins III052ce662010-09-13 14:44:16 -040043import android.provider.BrowserContract;
John Reck2eec4c32011-05-11 15:55:32 -070044import android.provider.BrowserContract.Accounts;
Leon Scroggins25230d72010-09-28 20:09:25 -040045import android.text.TextUtils;
Leon Scroggins162f8352010-10-18 15:02:44 -040046import android.util.AttributeSet;
Leon Scroggins III052ce662010-09-13 14:44:16 -040047import android.view.KeyEvent;
48import android.view.LayoutInflater;
The Android Open Source Project0c908882009-03-03 19:32:16 -080049import android.view.View;
Leon Scroggins III052ce662010-09-13 14:44:16 -040050import android.view.ViewGroup;
The Android Open Source Project0c908882009-03-03 19:32:16 -080051import android.view.Window;
Leon Scroggins III76a0e9c2010-10-05 16:10:01 -040052import android.view.WindowManager;
Leon Scroggins III052ce662010-09-13 14:44:16 -040053import android.view.inputmethod.EditorInfo;
54import android.view.inputmethod.InputMethodManager;
55import android.widget.AdapterView;
John Reck2eec4c32011-05-11 15:55:32 -070056import android.widget.AdapterView.OnItemSelectedListener;
57import android.widget.ArrayAdapter;
Leon Scroggins III052ce662010-09-13 14:44:16 -040058import android.widget.CursorAdapter;
The Android Open Source Project0c908882009-03-03 19:32:16 -080059import android.widget.EditText;
Leon Scroggins III052ce662010-09-13 14:44:16 -040060import android.widget.ListView;
John Reck2eec4c32011-05-11 15:55:32 -070061import android.widget.Spinner;
The Android Open Source Project0c908882009-03-03 19:32:16 -080062import android.widget.TextView;
63import android.widget.Toast;
64
luxiaoldbe4a622013-07-19 17:14:06 +080065import com.android.browser.BrowserUtils;
66import com.android.browser.addbookmark.FolderSpinner;
67import com.android.browser.addbookmark.FolderSpinnerAdapter;
68
Cary Clarkf2407c62009-09-04 12:25:10 -040069import java.net.URI;
70import java.net.URISyntaxException;
Leon Scroggins III052ce662010-09-13 14:44:16 -040071
72public class AddBookmarkPage extends Activity
73 implements View.OnClickListener, TextView.OnEditorActionListener,
Leon Scroggins74dbe012010-10-15 10:54:27 -040074 AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks<Cursor>,
John Reck2eec4c32011-05-11 15:55:32 -070075 BreadCrumbView.Controller, FolderSpinner.OnSetSelectionListener,
76 OnItemSelectedListener {
The Android Open Source Project0c908882009-03-03 19:32:16 -080077
Michael Kolb370a4f32010-10-06 10:45:32 -070078 public static final long DEFAULT_FOLDER_ID = -1;
Leon Scrogginsbc922852010-10-22 12:15:27 -040079 public static final String TOUCH_ICON_URL = "touch_icon_url";
80 // Place on an edited bookmark to remove the saved thumbnail
81 public static final String REMOVE_THUMBNAIL = "remove_thumbnail";
82 public static final String USER_AGENT = "user_agent";
Leon Scrogginsbdff8a72011-02-11 15:49:04 -050083 public static final String CHECK_FOR_DUPE = "check_for_dupe";
Michael Kolb370a4f32010-10-06 10:45:32 -070084
John Reckc8490812010-11-22 14:15:36 -080085 /* package */ static final String EXTRA_EDIT_BOOKMARK = "bookmark";
86 /* package */ static final String EXTRA_IS_FOLDER = "is_folder";
87
Leon Scroggins74dbe012010-10-15 10:54:27 -040088 private static final int MAX_CRUMBS_SHOWN = 2;
89
The Android Open Source Project0c908882009-03-03 19:32:16 -080090 private final String LOGTAG = "Bookmarks";
91
Leon Scroggins III052ce662010-09-13 14:44:16 -040092 // IDs for the CursorLoaders that are used.
John Reck2eec4c32011-05-11 15:55:32 -070093 private final int LOADER_ID_ACCOUNTS = 0;
94 private final int LOADER_ID_FOLDER_CONTENTS = 1;
95 private final int LOADER_ID_EDIT_INFO = 2;
Leon Scroggins III052ce662010-09-13 14:44:16 -040096
The Android Open Source Project0c908882009-03-03 19:32:16 -080097 private EditText mTitle;
98 private EditText mAddress;
99 private TextView mButton;
100 private View mCancelButton;
101 private boolean mEditingExisting;
John Reckc8490812010-11-22 14:15:36 -0800102 private boolean mEditingFolder;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800103 private Bundle mMap;
Patrick Scott3918d442009-08-04 13:22:29 -0400104 private String mTouchIconUrl;
Ben Murdochaac7aa62009-09-17 16:57:40 +0100105 private String mOriginalUrl;
Leon Scroggins504433a2011-01-13 12:26:52 -0500106 private FolderSpinner mFolder;
Leon Scroggins III052ce662010-09-13 14:44:16 -0400107 private View mDefaultView;
108 private View mFolderSelector;
109 private EditText mFolderNamer;
Leon Scroggins0e3a7b82011-01-11 19:08:03 -0500110 private View mFolderCancel;
Leon Scroggins162f8352010-10-18 15:02:44 -0400111 private boolean mIsFolderNamerShowing;
112 private View mFolderNamerHolder;
Leon Scroggins III052ce662010-09-13 14:44:16 -0400113 private View mAddNewFolder;
Leon Scroggins7e5f7352010-10-18 13:25:31 -0400114 private View mAddSeparator;
Leon Scrogginsb3ae8802011-01-18 11:55:27 -0500115 private long mCurrentFolder;
Leon Scroggins III052ce662010-09-13 14:44:16 -0400116 private FolderAdapter mAdapter;
Leon Scroggins74dbe012010-10-15 10:54:27 -0400117 private BreadCrumbView mCrumbs;
Leon Scroggins7e5f7352010-10-18 13:25:31 -0400118 private TextView mFakeTitle;
119 private View mCrumbHolder;
Leon Scroggins162f8352010-10-18 15:02:44 -0400120 private CustomListView mListView;
Leon Scroggins88d08032010-10-21 15:17:10 -0400121 private boolean mSaveToHomeScreen;
Leon Scroggins02081942010-11-01 17:52:42 -0400122 private long mRootFolder;
Leon Scroggins905250c2010-12-17 15:25:33 -0500123 private TextView mTopLevelLabel;
124 private Drawable mHeaderIcon;
Leon Scroggins75630672011-01-13 17:56:15 -0500125 private View mRemoveLink;
126 private View mFakeTitleHolder;
Leon Scroggins2f24e992011-02-11 14:02:10 -0500127 private FolderSpinnerAdapter mFolderAdapter;
John Reck2eec4c32011-05-11 15:55:32 -0700128 private Spinner mAccountSpinner;
129 private ArrayAdapter<BookmarkAccount> mAccountAdapter;
luxiaoldbe4a622013-07-19 17:14:06 +0800130 // add for carrier which requires same title or address can not exist.
131 private long mDuplicateId;
132 private Context mDuplicateContext;
John Reck2eec4c32011-05-11 15:55:32 -0700133
Leon Scroggins III052ce662010-09-13 14:44:16 -0400134 private static class Folder {
135 String Name;
136 long Id;
137 Folder(String name, long id) {
138 Name = name;
139 Id = id;
140 }
141 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800142
Ben Murdoch1794fe22009-09-29 18:14:30 +0100143 // Message IDs
144 private static final int SAVE_BOOKMARK = 100;
Leon Scroggins88d08032010-10-21 15:17:10 -0400145 private static final int TOUCH_ICON_DOWNLOADED = 101;
Leon Scroggins75630672011-01-13 17:56:15 -0500146 private static final int BOOKMARK_DELETED = 102;
Ben Murdoch1794fe22009-09-29 18:14:30 +0100147
148 private Handler mHandler;
149
Bjorn Bringertb1402a52010-10-12 10:53:12 +0100150 private InputMethodManager getInputMethodManager() {
151 return (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
152 }
153
Leon Scroggins8baaa632010-12-08 19:46:53 -0500154 private Uri getUriForFolder(long folder) {
John Reck903a0722011-11-09 17:53:10 -0800155 BookmarkAccount account =
156 (BookmarkAccount) mAccountSpinner.getSelectedItem();
157 if (folder == mRootFolder && account != null) {
158 return BookmarksLoader.addAccount(
159 BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER,
160 account.accountType, account.accountName);
161 }
John Reck2eec4c32011-05-11 15:55:32 -0700162 return BrowserContract.Bookmarks.buildFolderUri(folder);
Leon Scroggins8baaa632010-12-08 19:46:53 -0500163 }
164
Leon Scroggins III052ce662010-09-13 14:44:16 -0400165 @Override
John Reck71efc2b2011-05-09 16:54:28 -0700166 public void onTop(BreadCrumbView view, int level, Object data) {
Leon Scroggins74dbe012010-10-15 10:54:27 -0400167 if (null == data) return;
Leon Scroggins52f7daa2010-10-18 16:57:46 -0400168 Folder folderData = (Folder) data;
169 long folder = folderData.Id;
Leon Scroggins74dbe012010-10-15 10:54:27 -0400170 LoaderManager manager = getLoaderManager();
John Reck2eec4c32011-05-11 15:55:32 -0700171 CursorLoader loader = (CursorLoader) ((Loader<?>) manager.getLoader(
Leon Scroggins74dbe012010-10-15 10:54:27 -0400172 LOADER_ID_FOLDER_CONTENTS));
Leon Scroggins8baaa632010-12-08 19:46:53 -0500173 loader.setUri(getUriForFolder(folder));
Leon Scroggins74dbe012010-10-15 10:54:27 -0400174 loader.forceLoad();
Leon Scroggins162f8352010-10-18 15:02:44 -0400175 if (mIsFolderNamerShowing) {
Leon Scroggins6573f9e2010-10-18 17:22:35 -0400176 completeOrCancelFolderNaming(true);
177 }
Leon Scroggins905250c2010-12-17 15:25:33 -0500178 setShowBookmarkIcon(level == 1);
179 }
180
181 /**
182 * Show or hide the icon for bookmarks next to "Bookmarks" in the crumb view.
183 * @param show True if the icon should visible, false otherwise.
184 */
185 private void setShowBookmarkIcon(boolean show) {
186 Drawable drawable = show ? mHeaderIcon: null;
187 mTopLevelLabel.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
Leon Scroggins74dbe012010-10-15 10:54:27 -0400188 }
189
Leon Scroggins74dbe012010-10-15 10:54:27 -0400190 @Override
Leon Scroggins III052ce662010-09-13 14:44:16 -0400191 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
192 if (v == mFolderNamer) {
193 if (v.getText().length() > 0) {
194 if (actionId == EditorInfo.IME_NULL) {
195 // Only want to do this once.
196 if (event.getAction() == KeyEvent.ACTION_UP) {
Leon Scroggins6573f9e2010-10-18 17:22:35 -0400197 completeOrCancelFolderNaming(false);
Leon Scroggins III052ce662010-09-13 14:44:16 -0400198 }
Leon Scroggins III052ce662010-09-13 14:44:16 -0400199 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800200 }
Michael Kolb31829b92010-10-01 11:50:21 -0700201 // Steal the key press; otherwise a newline will be added
202 return true;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800203 }
Leon Scroggins III052ce662010-09-13 14:44:16 -0400204 return false;
205 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800206
Leon Scroggins52f7daa2010-10-18 16:57:46 -0400207 private void switchToDefaultView(boolean changedFolder) {
208 mFolderSelector.setVisibility(View.GONE);
209 mDefaultView.setVisibility(View.VISIBLE);
210 mCrumbHolder.setVisibility(View.GONE);
Leon Scroggins75630672011-01-13 17:56:15 -0500211 mFakeTitleHolder.setVisibility(View.VISIBLE);
Leon Scroggins52f7daa2010-10-18 16:57:46 -0400212 if (changedFolder) {
213 Object data = mCrumbs.getTopData();
214 if (data != null) {
215 Folder folder = (Folder) data;
216 mCurrentFolder = folder.Id;
Leon Scrogginsdd13bad2011-01-06 20:25:54 -0500217 if (mCurrentFolder == mRootFolder) {
218 // The Spinner changed to show "Other folder ..." Change
219 // it back to "Bookmarks", which is position 0 if we are
220 // editing a folder, 1 otherwise.
Leon Scroggins504433a2011-01-13 12:26:52 -0500221 mFolder.setSelectionIgnoringSelectionChange(mEditingFolder ? 0 : 1);
Leon Scrogginsdd13bad2011-01-06 20:25:54 -0500222 } else {
John Reck2eec4c32011-05-11 15:55:32 -0700223 mFolderAdapter.setOtherFolderDisplayText(folder.Name);
Leon Scrogginsdd13bad2011-01-06 20:25:54 -0500224 }
225 }
226 } else {
227 // The user canceled selecting a folder. Revert back to the earlier
228 // selection.
229 if (mSaveToHomeScreen) {
Leon Scroggins504433a2011-01-13 12:26:52 -0500230 mFolder.setSelectionIgnoringSelectionChange(0);
Leon Scrogginsdd13bad2011-01-06 20:25:54 -0500231 } else {
Leon Scrogginsb3ae8802011-01-18 11:55:27 -0500232 if (mCurrentFolder == mRootFolder) {
233 mFolder.setSelectionIgnoringSelectionChange(mEditingFolder ? 0 : 1);
234 } else {
235 Object data = mCrumbs.getTopData();
236 if (data != null && ((Folder) data).Id == mCurrentFolder) {
John Reck2eec4c32011-05-11 15:55:32 -0700237 // We are showing the correct folder hierarchy. The
Leon Scrogginsb3ae8802011-01-18 11:55:27 -0500238 // folder selector will say "Other folder..." Change it
239 // to say the name of the folder once again.
John Reck2eec4c32011-05-11 15:55:32 -0700240 mFolderAdapter.setOtherFolderDisplayText(((Folder) data).Name);
Leon Scrogginsb3ae8802011-01-18 11:55:27 -0500241 } else {
John Reck2eec4c32011-05-11 15:55:32 -0700242 // We are not showing the correct folder hierarchy.
Leon Scrogginsb3ae8802011-01-18 11:55:27 -0500243 // Clear the Crumbs and find the proper folder
Leon Scrogginsb3ae8802011-01-18 11:55:27 -0500244 setupTopCrumb();
245 LoaderManager manager = getLoaderManager();
Leon Scrogginsb3ae8802011-01-18 11:55:27 -0500246 manager.restartLoader(LOADER_ID_FOLDER_CONTENTS, null, this);
247
248 }
249 }
Leon Scroggins52f7daa2010-10-18 16:57:46 -0400250 }
251 }
252 }
253
Leon Scroggins III052ce662010-09-13 14:44:16 -0400254 @Override
255 public void onClick(View v) {
256 if (v == mButton) {
257 if (mFolderSelector.getVisibility() == View.VISIBLE) {
Leon Scroggins52f7daa2010-10-18 16:57:46 -0400258 // We are showing the folder selector.
Leon Scroggins162f8352010-10-18 15:02:44 -0400259 if (mIsFolderNamerShowing) {
Leon Scroggins6573f9e2010-10-18 17:22:35 -0400260 completeOrCancelFolderNaming(false);
Michael Kolbd40ac1a2010-09-29 00:23:46 -0700261 } else {
262 // User has selected a folder. Go back to the opening page
Leon Scroggins88d08032010-10-21 15:17:10 -0400263 mSaveToHomeScreen = false;
Leon Scroggins52f7daa2010-10-18 16:57:46 -0400264 switchToDefaultView(true);
Michael Kolbd40ac1a2010-09-29 00:23:46 -0700265 }
luxiaoldbe4a622013-07-19 17:14:06 +0800266 } else {
267 // add for carrier which requires same title or address can not
268 // exist.
269 if (mSaveToHomeScreen) {
270 if (save()) {
271 return;
272 }
273 } else {
274 onSaveWithConfirm();
275 }
Leon Scroggins III052ce662010-09-13 14:44:16 -0400276 }
277 } else if (v == mCancelButton) {
Leon Scroggins162f8352010-10-18 15:02:44 -0400278 if (mIsFolderNamerShowing) {
Leon Scroggins6573f9e2010-10-18 17:22:35 -0400279 completeOrCancelFolderNaming(true);
Leon Scroggins52f7daa2010-10-18 16:57:46 -0400280 } else if (mFolderSelector.getVisibility() == View.VISIBLE) {
281 switchToDefaultView(false);
Michael Kolbd40ac1a2010-09-29 00:23:46 -0700282 } else {
283 finish();
284 }
Leon Scroggins0e3a7b82011-01-11 19:08:03 -0500285 } else if (v == mFolderCancel) {
286 completeOrCancelFolderNaming(true);
Leon Scroggins III052ce662010-09-13 14:44:16 -0400287 } else if (v == mAddNewFolder) {
Leon Scroggins162f8352010-10-18 15:02:44 -0400288 setShowFolderNamer(true);
Leon Scroggins III052ce662010-09-13 14:44:16 -0400289 mFolderNamer.setText(R.string.new_folder);
290 mFolderNamer.requestFocus();
Michael Kolbd40ac1a2010-09-29 00:23:46 -0700291 mAddNewFolder.setVisibility(View.GONE);
Leon Scroggins7e5f7352010-10-18 13:25:31 -0400292 mAddSeparator.setVisibility(View.GONE);
Leon Scroggins162f8352010-10-18 15:02:44 -0400293 InputMethodManager imm = getInputMethodManager();
294 // Set the InputMethodManager to focus on the ListView so that it
295 // can transfer the focus to mFolderNamer.
296 imm.focusIn(mListView);
297 imm.showSoftInput(mFolderNamer, InputMethodManager.SHOW_IMPLICIT);
Leon Scroggins75630672011-01-13 17:56:15 -0500298 } else if (v == mRemoveLink) {
299 if (!mEditingExisting) {
300 throw new AssertionError("Remove button should not be shown for"
301 + " new bookmarks");
302 }
303 long id = mMap.getLong(BrowserContract.Bookmarks._ID);
304 createHandler();
305 Message msg = Message.obtain(mHandler, BOOKMARK_DELETED);
306 BookmarkUtils.displayRemoveBookmarkDialog(id,
307 mTitle.getText().toString(), this, msg);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800308 }
Leon Scroggins III052ce662010-09-13 14:44:16 -0400309 }
310
Leon Scroggins504433a2011-01-13 12:26:52 -0500311 // FolderSpinner.OnSetSelectionListener
312
Leon Scroggins88d08032010-10-21 15:17:10 -0400313 @Override
Leon Scroggins504433a2011-01-13 12:26:52 -0500314 public void onSetSelection(long id) {
Leon Scrogginsdd13bad2011-01-06 20:25:54 -0500315 int intId = (int) id;
316 switch (intId) {
317 case FolderSpinnerAdapter.ROOT_FOLDER:
Leon Scroggins02081942010-11-01 17:52:42 -0400318 mCurrentFolder = mRootFolder;
Leon Scroggins88d08032010-10-21 15:17:10 -0400319 mSaveToHomeScreen = false;
320 break;
Leon Scrogginsdd13bad2011-01-06 20:25:54 -0500321 case FolderSpinnerAdapter.HOME_SCREEN:
Leon Scroggins88d08032010-10-21 15:17:10 -0400322 // Create a short cut to the home screen
323 mSaveToHomeScreen = true;
Leon Scroggins88d08032010-10-21 15:17:10 -0400324 break;
Leon Scrogginsdd13bad2011-01-06 20:25:54 -0500325 case FolderSpinnerAdapter.OTHER_FOLDER:
Leon Scroggins88d08032010-10-21 15:17:10 -0400326 switchToFolderSelector();
327 break;
Leon Scroggins2f24e992011-02-11 14:02:10 -0500328 case FolderSpinnerAdapter.RECENT_FOLDER:
329 mCurrentFolder = mFolderAdapter.recentFolderId();
330 mSaveToHomeScreen = false;
331 // In case the user decides to select OTHER_FOLDER
332 // and choose a different one, so that we will start from
333 // the correct place.
334 LoaderManager manager = getLoaderManager();
Leon Scroggins2f24e992011-02-11 14:02:10 -0500335 manager.restartLoader(LOADER_ID_FOLDER_CONTENTS, null, this);
Leon Scroggins0b95ad42011-02-23 15:23:48 -0500336 break;
Leon Scroggins88d08032010-10-21 15:17:10 -0400337 default:
Leon Scrogginsdd13bad2011-01-06 20:25:54 -0500338 break;
Leon Scroggins88d08032010-10-21 15:17:10 -0400339 }
Leon Scrogginsdd13bad2011-01-06 20:25:54 -0500340 }
341
Leon Scroggins0e3a7b82011-01-11 19:08:03 -0500342 /**
343 * Finish naming a folder, and close the IME
344 * @param cancel If true, the new folder is not created. If false, the new
345 * folder is created and the user is taken inside it.
346 */
Leon Scroggins6573f9e2010-10-18 17:22:35 -0400347 private void completeOrCancelFolderNaming(boolean cancel) {
348 if (!cancel && !TextUtils.isEmpty(mFolderNamer.getText())) {
Michael Kolb31829b92010-10-01 11:50:21 -0700349 String name = mFolderNamer.getText().toString();
350 long id = addFolderToCurrent(mFolderNamer.getText().toString());
351 descendInto(name, id);
Michael Kolb31829b92010-10-01 11:50:21 -0700352 }
Leon Scroggins162f8352010-10-18 15:02:44 -0400353 setShowFolderNamer(false);
Leon Scroggins6573f9e2010-10-18 17:22:35 -0400354 mAddNewFolder.setVisibility(View.VISIBLE);
355 mAddSeparator.setVisibility(View.VISIBLE);
356 getInputMethodManager().hideSoftInputFromWindow(
Leon Scroggins162f8352010-10-18 15:02:44 -0400357 mListView.getWindowToken(), 0);
Michael Kolb31829b92010-10-01 11:50:21 -0700358 }
359
Michael Kolbd40ac1a2010-09-29 00:23:46 -0700360 private long addFolderToCurrent(String name) {
361 // Add the folder to the database
362 ContentValues values = new ContentValues();
363 values.put(BrowserContract.Bookmarks.TITLE,
364 name);
365 values.put(BrowserContract.Bookmarks.IS_FOLDER, 1);
Leon Scroggins52f7daa2010-10-18 16:57:46 -0400366 long currentFolder;
367 Object data = mCrumbs.getTopData();
368 if (data != null) {
369 currentFolder = ((Folder) data).Id;
370 } else {
Leon Scroggins02081942010-11-01 17:52:42 -0400371 currentFolder = mRootFolder;
Leon Scroggins52f7daa2010-10-18 16:57:46 -0400372 }
373 values.put(BrowserContract.Bookmarks.PARENT, currentFolder);
Michael Kolbd40ac1a2010-09-29 00:23:46 -0700374 Uri uri = getContentResolver().insert(
375 BrowserContract.Bookmarks.CONTENT_URI, values);
376 if (uri != null) {
377 return ContentUris.parseId(uri);
378 } else {
379 return -1;
380 }
381 }
382
Leon Scroggins III052ce662010-09-13 14:44:16 -0400383 private void switchToFolderSelector() {
Leon Scrogginsdd13bad2011-01-06 20:25:54 -0500384 // Set the list to the top in case it is scrolled.
385 mListView.setSelection(0);
Leon Scroggins III052ce662010-09-13 14:44:16 -0400386 mDefaultView.setVisibility(View.GONE);
387 mFolderSelector.setVisibility(View.VISIBLE);
Leon Scroggins7e5f7352010-10-18 13:25:31 -0400388 mCrumbHolder.setVisibility(View.VISIBLE);
Leon Scroggins75630672011-01-13 17:56:15 -0500389 mFakeTitleHolder.setVisibility(View.GONE);
Leon Scroggins7e5f7352010-10-18 13:25:31 -0400390 mAddNewFolder.setVisibility(View.VISIBLE);
391 mAddSeparator.setVisibility(View.VISIBLE);
John Reck95f88e42011-09-26 09:25:43 -0700392 getInputMethodManager().hideSoftInputFromWindow(
393 mListView.getWindowToken(), 0);
Leon Scroggins III052ce662010-09-13 14:44:16 -0400394 }
395
Michael Kolbd40ac1a2010-09-29 00:23:46 -0700396 private void descendInto(String foldername, long id) {
Michael Kolb370a4f32010-10-06 10:45:32 -0700397 if (id != DEFAULT_FOLDER_ID) {
Leon Scroggins52f7daa2010-10-18 16:57:46 -0400398 mCrumbs.pushView(foldername, new Folder(foldername, id));
Leon Scroggins74dbe012010-10-15 10:54:27 -0400399 mCrumbs.notifyController();
Michael Kolbd40ac1a2010-09-29 00:23:46 -0700400 }
401 }
402
John Reck2eec4c32011-05-11 15:55:32 -0700403 private LoaderCallbacks<EditBookmarkInfo> mEditInfoLoaderCallbacks =
404 new LoaderCallbacks<EditBookmarkInfo>() {
405
406 @Override
407 public void onLoaderReset(Loader<EditBookmarkInfo> loader) {
408 // Don't care
409 }
410
411 @Override
412 public void onLoadFinished(Loader<EditBookmarkInfo> loader,
413 EditBookmarkInfo info) {
414 boolean setAccount = false;
415 if (info.id != -1) {
416 mEditingExisting = true;
417 showRemoveButton();
418 mFakeTitle.setText(R.string.edit_bookmark);
419 mTitle.setText(info.title);
420 mFolderAdapter.setOtherFolderDisplayText(info.parentTitle);
421 mMap.putLong(BrowserContract.Bookmarks._ID, info.id);
422 setAccount = true;
423 setAccount(info.accountName, info.accountType);
424 mCurrentFolder = info.parentId;
425 onCurrentFolderFound();
426 }
John Reck37894a92011-05-13 12:47:53 -0700427 // TODO: Detect if lastUsedId is a subfolder of info.id in the
428 // editing folder case. For now, just don't show the last used
429 // folder at all to prevent any chance of the user adding a parent
430 // folder to a child folder
431 if (info.lastUsedId != -1 && info.lastUsedId != info.id
432 && !mEditingFolder) {
John Reck2eec4c32011-05-11 15:55:32 -0700433 if (setAccount && info.lastUsedId != mRootFolder
434 && TextUtils.equals(info.lastUsedAccountName, info.accountName)
435 && TextUtils.equals(info.lastUsedAccountType, info.accountType)) {
436 mFolderAdapter.addRecentFolder(info.lastUsedId, info.lastUsedTitle);
437 } else if (!setAccount) {
438 setAccount = true;
439 setAccount(info.lastUsedAccountName, info.lastUsedAccountType);
440 if (info.lastUsedId != mRootFolder) {
441 mFolderAdapter.addRecentFolder(info.lastUsedId,
442 info.lastUsedTitle);
443 }
444 }
445 }
446 if (!setAccount) {
447 mAccountSpinner.setSelection(0);
448 }
449 }
450
451 @Override
452 public Loader<EditBookmarkInfo> onCreateLoader(int id, Bundle args) {
453 return new EditBookmarkInfoLoader(AddBookmarkPage.this, mMap);
454 }
455 };
456
457 void setAccount(String accountName, String accountType) {
458 for (int i = 0; i < mAccountAdapter.getCount(); i++) {
459 BookmarkAccount account = mAccountAdapter.getItem(i);
460 if (TextUtils.equals(account.accountName, accountName)
461 && TextUtils.equals(account.accountType, accountType)) {
John Reck2eec4c32011-05-11 15:55:32 -0700462 mAccountSpinner.setSelection(i);
John Reck903a0722011-11-09 17:53:10 -0800463 onRootFolderFound(account.rootFolderId);
John Reck2eec4c32011-05-11 15:55:32 -0700464 return;
465 }
466 }
467 }
468
Leon Scroggins III052ce662010-09-13 14:44:16 -0400469 @Override
470 public Loader<Cursor> onCreateLoader(int id, Bundle args) {
471 String[] projection;
472 switch (id) {
John Reck2eec4c32011-05-11 15:55:32 -0700473 case LOADER_ID_ACCOUNTS:
474 return new AccountsLoader(this);
Leon Scroggins III052ce662010-09-13 14:44:16 -0400475 case LOADER_ID_FOLDER_CONTENTS:
476 projection = new String[] {
477 BrowserContract.Bookmarks._ID,
478 BrowserContract.Bookmarks.TITLE,
479 BrowserContract.Bookmarks.IS_FOLDER
480 };
Leon Scrogginsc1129902010-12-08 15:28:33 -0500481 String where = BrowserContract.Bookmarks.IS_FOLDER + " != 0";
John Reck1dd8cd42011-05-13 11:22:09 -0700482 String whereArgs[] = null;
Leon Scrogginsc1129902010-12-08 15:28:33 -0500483 if (mEditingFolder) {
John Reck1dd8cd42011-05-13 11:22:09 -0700484 where += " AND " + BrowserContract.Bookmarks._ID + " != ?";
485 whereArgs = new String[] { Long.toString(mMap.getLong(
486 BrowserContract.Bookmarks._ID)) };
487 }
488 long currentFolder;
489 Object data = mCrumbs.getTopData();
490 if (data != null) {
491 currentFolder = ((Folder) data).Id;
492 } else {
493 currentFolder = mRootFolder;
Leon Scrogginsc1129902010-12-08 15:28:33 -0500494 }
Leon Scroggins III052ce662010-09-13 14:44:16 -0400495 return new CursorLoader(this,
John Reck1dd8cd42011-05-13 11:22:09 -0700496 getUriForFolder(currentFolder),
Leon Scroggins III052ce662010-09-13 14:44:16 -0400497 projection,
Leon Scrogginsc1129902010-12-08 15:28:33 -0500498 where,
John Reck1dd8cd42011-05-13 11:22:09 -0700499 whereArgs,
Leon Scroggins8baaa632010-12-08 19:46:53 -0500500 BrowserContract.Bookmarks._ID + " ASC");
Leon Scroggins III052ce662010-09-13 14:44:16 -0400501 default:
502 throw new AssertionError("Asking for nonexistant loader!");
503 }
504 }
505
506 @Override
507 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
508 switch (loader.getId()) {
John Reck2eec4c32011-05-11 15:55:32 -0700509 case LOADER_ID_ACCOUNTS:
510 mAccountAdapter.clear();
511 while (cursor.moveToNext()) {
512 mAccountAdapter.add(new BookmarkAccount(this, cursor));
Leon Scroggins504433a2011-01-13 12:26:52 -0500513 }
John Reck2eec4c32011-05-11 15:55:32 -0700514 getLoaderManager().destroyLoader(LOADER_ID_ACCOUNTS);
515 getLoaderManager().restartLoader(LOADER_ID_EDIT_INFO, null,
516 mEditInfoLoaderCallbacks);
Leon Scroggins504433a2011-01-13 12:26:52 -0500517 break;
Leon Scroggins III052ce662010-09-13 14:44:16 -0400518 case LOADER_ID_FOLDER_CONTENTS:
519 mAdapter.changeCursor(cursor);
520 break;
Leon Scroggins III052ce662010-09-13 14:44:16 -0400521 }
522 }
523
Dianne Hackborn39772c82010-12-16 00:43:54 -0800524 public void onLoaderReset(Loader<Cursor> loader) {
525 switch (loader.getId()) {
526 case LOADER_ID_FOLDER_CONTENTS:
527 mAdapter.changeCursor(null);
528 break;
529 }
530 }
531
Leon Scroggins02081942010-11-01 17:52:42 -0400532 /**
Leon Scroggins8baaa632010-12-08 19:46:53 -0500533 * Move cursor to the position that has folderToFind as its "_id".
534 * @param cursor Cursor containing folders in the bookmarks database
535 * @param folderToFind "_id" of the folder to move to.
536 * @param idIndex Index in cursor of "_id"
537 * @throws AssertionError if cursor is empty or there is no row with folderToFind
538 * as its "_id".
539 */
540 void moveCursorToFolder(Cursor cursor, long folderToFind, int idIndex)
541 throws AssertionError {
542 if (!cursor.moveToFirst()) {
543 throw new AssertionError("No folders in the database!");
544 }
545 long folder;
546 do {
547 folder = cursor.getLong(idIndex);
548 } while (folder != folderToFind && cursor.moveToNext());
549 if (cursor.isAfterLast()) {
550 throw new AssertionError("Folder(id=" + folderToFind
551 + ") holding this bookmark does not exist!");
552 }
553 }
554
Leon Scroggins III052ce662010-09-13 14:44:16 -0400555 @Override
556 public void onItemClick(AdapterView<?> parent, View view, int position,
557 long id) {
Leon Scrogginsd14cb122010-09-29 16:01:48 -0400558 TextView tv = (TextView) view.findViewById(android.R.id.text1);
Leon Scroggins III052ce662010-09-13 14:44:16 -0400559 // Switch to the folder that was clicked on.
Leon Scrogginsd14cb122010-09-29 16:01:48 -0400560 descendInto(tv.getText().toString(), id);
Leon Scroggins III052ce662010-09-13 14:44:16 -0400561 }
562
Leon Scroggins162f8352010-10-18 15:02:44 -0400563 private void setShowFolderNamer(boolean show) {
564 if (show != mIsFolderNamerShowing) {
565 mIsFolderNamerShowing = show;
566 if (show) {
567 // Set the selection to the folder namer so it will be in
568 // view.
569 mListView.addFooterView(mFolderNamerHolder);
570 } else {
571 mListView.removeFooterView(mFolderNamerHolder);
572 }
573 // Refresh the list.
574 mListView.setAdapter(mAdapter);
575 if (show) {
576 mListView.setSelection(mListView.getCount() - 1);
577 }
578 }
579 }
580
Leon Scroggins III052ce662010-09-13 14:44:16 -0400581 /**
582 * Shows a list of names of folders.
583 */
584 private class FolderAdapter extends CursorAdapter {
585 public FolderAdapter(Context context) {
586 super(context, null);
587 }
588
589 @Override
590 public void bindView(View view, Context context, Cursor cursor) {
591 ((TextView) view.findViewById(android.R.id.text1)).setText(
592 cursor.getString(cursor.getColumnIndexOrThrow(
593 BrowserContract.Bookmarks.TITLE)));
594 }
595
596 @Override
597 public View newView(Context context, Cursor cursor, ViewGroup parent) {
Michael Kolbd40ac1a2010-09-29 00:23:46 -0700598 View view = LayoutInflater.from(context).inflate(
599 R.layout.folder_list_item, null);
600 view.setBackgroundDrawable(context.getResources().
601 getDrawable(android.R.drawable.list_selector_background));
602 return view;
Leon Scroggins III052ce662010-09-13 14:44:16 -0400603 }
Leon Scroggins6573f9e2010-10-18 17:22:35 -0400604
605 @Override
606 public boolean isEmpty() {
607 // Do not show the empty view if the user is creating a new folder.
Leon Scroggins162f8352010-10-18 15:02:44 -0400608 return super.isEmpty() && !mIsFolderNamerShowing;
Leon Scroggins6573f9e2010-10-18 17:22:35 -0400609 }
Leon Scroggins III052ce662010-09-13 14:44:16 -0400610 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800611
Leon Scrogginsc1129902010-12-08 15:28:33 -0500612 @Override
The Android Open Source Project0c908882009-03-03 19:32:16 -0800613 protected void onCreate(Bundle icicle) {
614 super.onCreate(icicle);
Leon Scroggins7453ff22010-12-15 16:03:59 -0500615 requestWindowFeature(Window.FEATURE_NO_TITLE);
Ben Murdocheecb4e62010-07-06 16:30:38 +0100616
617 mMap = getIntent().getExtras();
Ben Murdocheecb4e62010-07-06 16:30:38 +0100618
Leon Scroggins III052ce662010-09-13 14:44:16 -0400619 setContentView(R.layout.browser_add_bookmark);
Ben Murdocheecb4e62010-07-06 16:30:38 +0100620
Leon Scroggins III76a0e9c2010-10-05 16:10:01 -0400621 Window window = getWindow();
Michael Kolbd40ac1a2010-09-29 00:23:46 -0700622
The Android Open Source Project0c908882009-03-03 19:32:16 -0800623 String title = null;
624 String url = null;
Ben Murdocheecb4e62010-07-06 16:30:38 +0100625
Leon Scroggins52f7daa2010-10-18 16:57:46 -0400626 mFakeTitle = (TextView) findViewById(R.id.fake_title);
627
The Android Open Source Project0c908882009-03-03 19:32:16 -0800628 if (mMap != null) {
John Reckc8490812010-11-22 14:15:36 -0800629 Bundle b = mMap.getBundle(EXTRA_EDIT_BOOKMARK);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800630 if (b != null) {
John Reckc8490812010-11-22 14:15:36 -0800631 mEditingFolder = mMap.getBoolean(EXTRA_IS_FOLDER, false);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800632 mMap = b;
633 mEditingExisting = true;
Leon Scroggins7e5f7352010-10-18 13:25:31 -0400634 mFakeTitle.setText(R.string.edit_bookmark);
John Reckc8490812010-11-22 14:15:36 -0800635 if (mEditingFolder) {
636 findViewById(R.id.row_address).setVisibility(View.GONE);
Leon Scroggins75630672011-01-13 17:56:15 -0500637 } else {
638 showRemoveButton();
John Reckc8490812010-11-22 14:15:36 -0800639 }
Leon Scroggins III76a0e9c2010-10-05 16:10:01 -0400640 } else {
641 int gravity = mMap.getInt("gravity", -1);
642 if (gravity != -1) {
643 WindowManager.LayoutParams l = window.getAttributes();
644 l.gravity = gravity;
645 window.setAttributes(l);
646 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800647 }
Leon Scrogginsbc922852010-10-22 12:15:27 -0400648 title = mMap.getString(BrowserContract.Bookmarks.TITLE);
649 url = mOriginalUrl = mMap.getString(BrowserContract.Bookmarks.URL);
650 mTouchIconUrl = mMap.getString(TOUCH_ICON_URL);
Michael Kolb370a4f32010-10-06 10:45:32 -0700651 mCurrentFolder = mMap.getLong(BrowserContract.Bookmarks.PARENT, DEFAULT_FOLDER_ID);
Leon Scroggins25230d72010-09-28 20:09:25 -0400652 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800653
654 mTitle = (EditText) findViewById(R.id.title);
655 mTitle.setText(title);
luxiaoldbe4a622013-07-19 17:14:06 +0800656 BrowserUtils.maxLengthFilter(AddBookmarkPage.this, mTitle, BrowserUtils.FILENAME_MAX_LENGTH);
Ben Murdocheecb4e62010-07-06 16:30:38 +0100657
Leon Scroggins III052ce662010-09-13 14:44:16 -0400658 mAddress = (EditText) findViewById(R.id.address);
659 mAddress.setText(url);
luxiaoldbe4a622013-07-19 17:14:06 +0800660 BrowserUtils.maxLengthFilter(AddBookmarkPage.this, mAddress, BrowserUtils.ADDRESS_MAX_LENGTH);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800661
The Android Open Source Project0c908882009-03-03 19:32:16 -0800662 mButton = (TextView) findViewById(R.id.OK);
Leon Scroggins III052ce662010-09-13 14:44:16 -0400663 mButton.setOnClickListener(this);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800664
665 mCancelButton = findViewById(R.id.cancel);
Leon Scroggins III052ce662010-09-13 14:44:16 -0400666 mCancelButton.setOnClickListener(this);
667
Leon Scroggins504433a2011-01-13 12:26:52 -0500668 mFolder = (FolderSpinner) findViewById(R.id.folder);
John Reck2eec4c32011-05-11 15:55:32 -0700669 mFolderAdapter = new FolderSpinnerAdapter(this, !mEditingFolder);
Leon Scroggins2f24e992011-02-11 14:02:10 -0500670 mFolder.setAdapter(mFolderAdapter);
Leon Scroggins504433a2011-01-13 12:26:52 -0500671 mFolder.setOnSetSelectionListener(this);
Leon Scroggins III052ce662010-09-13 14:44:16 -0400672
673 mDefaultView = findViewById(R.id.default_view);
674 mFolderSelector = findViewById(R.id.folder_selector);
675
Leon Scroggins162f8352010-10-18 15:02:44 -0400676 mFolderNamerHolder = getLayoutInflater().inflate(R.layout.new_folder_layout, null);
677 mFolderNamer = (EditText) mFolderNamerHolder.findViewById(R.id.folder_namer);
Leon Scroggins III052ce662010-09-13 14:44:16 -0400678 mFolderNamer.setOnEditorActionListener(this);
luxiaoldbe4a622013-07-19 17:14:06 +0800679
680 // add for carrier test about warning limit of edit text
681 BrowserUtils.maxLengthFilter(AddBookmarkPage.this, mFolderNamer,
682 BrowserUtils.FILENAME_MAX_LENGTH);
683
Leon Scroggins0e3a7b82011-01-11 19:08:03 -0500684 mFolderCancel = mFolderNamerHolder.findViewById(R.id.close);
685 mFolderCancel.setOnClickListener(this);
Leon Scroggins III052ce662010-09-13 14:44:16 -0400686
687 mAddNewFolder = findViewById(R.id.add_new_folder);
688 mAddNewFolder.setOnClickListener(this);
Leon Scroggins7e5f7352010-10-18 13:25:31 -0400689 mAddSeparator = findViewById(R.id.add_divider);
Leon Scroggins III052ce662010-09-13 14:44:16 -0400690
Leon Scroggins74dbe012010-10-15 10:54:27 -0400691 mCrumbs = (BreadCrumbView) findViewById(R.id.crumbs);
692 mCrumbs.setUseBackButton(true);
693 mCrumbs.setController(this);
Michael Kolb5a72f182011-01-13 20:35:06 -0800694 mHeaderIcon = getResources().getDrawable(R.drawable.ic_folder_holo_dark);
Leon Scroggins7e5f7352010-10-18 13:25:31 -0400695 mCrumbHolder = findViewById(R.id.crumb_holder);
John Reck89f73c12010-12-01 10:10:14 -0800696 mCrumbs.setMaxVisible(MAX_CRUMBS_SHOWN);
Leon Scroggins III052ce662010-09-13 14:44:16 -0400697
Leon Scroggins III052ce662010-09-13 14:44:16 -0400698 mAdapter = new FolderAdapter(this);
Leon Scroggins162f8352010-10-18 15:02:44 -0400699 mListView = (CustomListView) findViewById(R.id.list);
Leon Scroggins6573f9e2010-10-18 17:22:35 -0400700 View empty = findViewById(R.id.empty);
701 mListView.setEmptyView(empty);
702 mListView.setAdapter(mAdapter);
703 mListView.setOnItemClickListener(this);
Leon Scroggins162f8352010-10-18 15:02:44 -0400704 mListView.addEditText(mFolderNamer);
Leon Scroggins504433a2011-01-13 12:26:52 -0500705
John Reck2eec4c32011-05-11 15:55:32 -0700706 mAccountAdapter = new ArrayAdapter<BookmarkAccount>(this,
707 android.R.layout.simple_spinner_item);
708 mAccountAdapter.setDropDownViewResource(
709 android.R.layout.simple_spinner_dropdown_item);
710 mAccountSpinner = (Spinner) findViewById(R.id.accounts);
711 mAccountSpinner.setAdapter(mAccountAdapter);
712 mAccountSpinner.setOnItemSelectedListener(this);
713
714
Leon Scroggins75630672011-01-13 17:56:15 -0500715 mFakeTitleHolder = findViewById(R.id.title_holder);
716
Leon Scroggins504433a2011-01-13 12:26:52 -0500717 if (!window.getDecorView().isInTouchMode()) {
718 mButton.requestFocus();
719 }
720
John Reck2eec4c32011-05-11 15:55:32 -0700721 getLoaderManager().restartLoader(LOADER_ID_ACCOUNTS, null, this);
Leon Scroggins504433a2011-01-13 12:26:52 -0500722 }
723
Leon Scroggins75630672011-01-13 17:56:15 -0500724 private void showRemoveButton() {
725 findViewById(R.id.remove_divider).setVisibility(View.VISIBLE);
726 mRemoveLink = findViewById(R.id.remove);
727 mRemoveLink.setVisibility(View.VISIBLE);
728 mRemoveLink.setOnClickListener(this);
729 }
730
Leon Scroggins504433a2011-01-13 12:26:52 -0500731 // Called once we have determined which folder is the root folder
732 private void onRootFolderFound(long root) {
733 mRootFolder = root;
John Reck2eec4c32011-05-11 15:55:32 -0700734 mCurrentFolder = mRootFolder;
Leon Scrogginsb3ae8802011-01-18 11:55:27 -0500735 setupTopCrumb();
John Reck2eec4c32011-05-11 15:55:32 -0700736 onCurrentFolderFound();
Leon Scroggins504433a2011-01-13 12:26:52 -0500737 }
738
Leon Scrogginsb3ae8802011-01-18 11:55:27 -0500739 private void setupTopCrumb() {
John Reck2eec4c32011-05-11 15:55:32 -0700740 mCrumbs.clear();
Leon Scrogginsb3ae8802011-01-18 11:55:27 -0500741 String name = getString(R.string.bookmarks);
742 mTopLevelLabel = (TextView) mCrumbs.pushView(name, false,
743 new Folder(name, mRootFolder));
744 // To better match the other folders.
745 mTopLevelLabel.setCompoundDrawablePadding(6);
746 }
747
Leon Scroggins504433a2011-01-13 12:26:52 -0500748 private void onCurrentFolderFound() {
Leon Scroggins III052ce662010-09-13 14:44:16 -0400749 LoaderManager manager = getLoaderManager();
Leon Scroggins8baaa632010-12-08 19:46:53 -0500750 if (mCurrentFolder != mRootFolder) {
Leon Scrogginsdd13bad2011-01-06 20:25:54 -0500751 // Since we're not in the root folder, change the selection to other
752 // folder now. The text will get changed once we select the correct
753 // folder.
Leon Scroggins504433a2011-01-13 12:26:52 -0500754 mFolder.setSelectionIgnoringSelectionChange(mEditingFolder ? 1 : 2);
Leon Scroggins905250c2010-12-17 15:25:33 -0500755 } else {
756 setShowBookmarkIcon(true);
Leon Scroggins504433a2011-01-13 12:26:52 -0500757 if (!mEditingFolder) {
758 // Initially the "Bookmarks" folder should be showing, rather than
759 // the home screen. In the editing folder case, home screen is not
760 // an option, so "Bookmarks" folder is already at the top.
761 mFolder.setSelectionIgnoringSelectionChange(FolderSpinnerAdapter.ROOT_FOLDER);
762 }
Leon Scroggins III052ce662010-09-13 14:44:16 -0400763 }
Leon Scroggins52f7daa2010-10-18 16:57:46 -0400764 // Find the contents of the current folder
John Reck2eec4c32011-05-11 15:55:32 -0700765 manager.restartLoader(LOADER_ID_FOLDER_CONTENTS, null, this);
Leon Scroggins8baaa632010-12-08 19:46:53 -0500766 }
767
Leon Scroggins02065b02010-01-04 14:30:13 -0500768 /**
769 * Runnable to save a bookmark, so it can be performed in its own thread.
770 */
771 private class SaveBookmarkRunnable implements Runnable {
Leon Scroggins III052ce662010-09-13 14:44:16 -0400772 // FIXME: This should be an async task.
Leon Scroggins02065b02010-01-04 14:30:13 -0500773 private Message mMessage;
Henrik Baard980e9952010-09-06 18:13:23 +0200774 private Context mContext;
775 public SaveBookmarkRunnable(Context ctx, Message msg) {
Ben Murdoch914c5592011-08-01 13:58:47 +0100776 mContext = ctx.getApplicationContext();
Leon Scroggins02065b02010-01-04 14:30:13 -0500777 mMessage = msg;
778 }
779 public void run() {
780 // Unbundle bookmark data.
781 Bundle bundle = mMessage.getData();
Leon Scrogginsbc922852010-10-22 12:15:27 -0400782 String title = bundle.getString(BrowserContract.Bookmarks.TITLE);
783 String url = bundle.getString(BrowserContract.Bookmarks.URL);
784 boolean invalidateThumbnail = bundle.getBoolean(REMOVE_THUMBNAIL);
Leon Scroggins02065b02010-01-04 14:30:13 -0500785 Bitmap thumbnail = invalidateThumbnail ? null
Leon Scrogginsbc922852010-10-22 12:15:27 -0400786 : (Bitmap) bundle.getParcelable(BrowserContract.Bookmarks.THUMBNAIL);
787 String touchIconUrl = bundle.getString(TOUCH_ICON_URL);
Leon Scroggins02065b02010-01-04 14:30:13 -0500788
789 // Save to the bookmarks DB.
790 try {
791 final ContentResolver cr = getContentResolver();
Leon Scroggins III052ce662010-09-13 14:44:16 -0400792 Bookmarks.addBookmark(AddBookmarkPage.this, false, url,
John Reckaf262e72011-07-25 13:55:44 -0700793 title, thumbnail, mCurrentFolder);
Leon Scroggins02065b02010-01-04 14:30:13 -0500794 if (touchIconUrl != null) {
Henrik Baard980e9952010-09-06 18:13:23 +0200795 new DownloadTouchIcon(mContext, cr, url).execute(mTouchIconUrl);
Leon Scroggins02065b02010-01-04 14:30:13 -0500796 }
797 mMessage.arg1 = 1;
798 } catch (IllegalStateException e) {
799 mMessage.arg1 = 0;
800 }
801 mMessage.sendToTarget();
802 }
803 }
804
John Reckc8490812010-11-22 14:15:36 -0800805 private static class UpdateBookmarkTask extends AsyncTask<ContentValues, Void, Void> {
806 Context mContext;
807 Long mId;
808
809 public UpdateBookmarkTask(Context context, long id) {
Ben Murdoch914c5592011-08-01 13:58:47 +0100810 mContext = context.getApplicationContext();
John Reckc8490812010-11-22 14:15:36 -0800811 mId = id;
812 }
813
814 @Override
815 protected Void doInBackground(ContentValues... params) {
816 if (params.length != 1) {
817 throw new IllegalArgumentException("No ContentValues provided!");
818 }
819 Uri uri = ContentUris.withAppendedId(BookmarkUtils.getBookmarksUri(mContext), mId);
820 mContext.getContentResolver().update(
821 uri,
822 params[0], null, null);
823 return null;
824 }
825 }
826
Ben Murdoch1794fe22009-09-29 18:14:30 +0100827 private void createHandler() {
828 if (mHandler == null) {
829 mHandler = new Handler() {
830 @Override
831 public void handleMessage(Message msg) {
832 switch (msg.what) {
833 case SAVE_BOOKMARK:
Leon Scroggins02065b02010-01-04 14:30:13 -0500834 if (1 == msg.arg1) {
Ben Murdoch1794fe22009-09-29 18:14:30 +0100835 Toast.makeText(AddBookmarkPage.this, R.string.bookmark_saved,
836 Toast.LENGTH_LONG).show();
837 } else {
838 Toast.makeText(AddBookmarkPage.this, R.string.bookmark_not_saved,
839 Toast.LENGTH_LONG).show();
840 }
841 break;
Leon Scroggins88d08032010-10-21 15:17:10 -0400842 case TOUCH_ICON_DOWNLOADED:
843 Bundle b = msg.getData();
844 sendBroadcast(BookmarkUtils.createAddToHomeIntent(
Leon Scrogginsbc922852010-10-22 12:15:27 -0400845 AddBookmarkPage.this,
846 b.getString(BrowserContract.Bookmarks.URL),
847 b.getString(BrowserContract.Bookmarks.TITLE),
848 (Bitmap) b.getParcelable(BrowserContract.Bookmarks.TOUCH_ICON),
849 (Bitmap) b.getParcelable(BrowserContract.Bookmarks.FAVICON)));
Leon Scroggins88d08032010-10-21 15:17:10 -0400850 break;
Leon Scroggins75630672011-01-13 17:56:15 -0500851 case BOOKMARK_DELETED:
852 finish();
853 break;
Ben Murdoch1794fe22009-09-29 18:14:30 +0100854 }
855 }
856 };
857 }
858 }
859
luxiaoldbe4a622013-07-19 17:14:06 +0800860 static void deleteDuplicateBookmark(final Context context, final long id) {
861 Uri uri = ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI, id);
862 context.getContentResolver().delete(uri, null, null);
863 }
864
865 private void onSaveWithConfirm() {
866 String title = mTitle.getText().toString().trim();
867 String unfilteredUrl = UrlUtils.fixUrl(mAddress.getText().toString());
868 String url = unfilteredUrl.trim();
869 Long id = mMap.getLong(BrowserContract.Bookmarks._ID);
870 int duplicateCount;
871 final ContentResolver cr = getContentResolver();
872
873 Cursor cursor = cr.query(BrowserContract.Bookmarks.CONTENT_URI,
874 BookmarksLoader.PROJECTION,
875 "( title = ? OR url = ? ) AND parent = ?",
876 new String[] {
877 title, url, Long.toString(mCurrentFolder)
878 },
879 null);
880
881 if (cursor == null) {
882 save();
883 return;
884 }
885
886 duplicateCount = cursor.getCount();
887 if (duplicateCount <= 0) {
888 cursor.close();
889 save();
890 return;
891 } else {
892 try {
893 while (cursor.moveToNext()) {
894 mDuplicateId = cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID);
895 mDuplicateContext = AddBookmarkPage.this;
896 }
897 } catch (IllegalStateException e) {
898 e.printStackTrace();
899 } finally {
900 if (cursor != null)
901 cursor.close();
902 }
903 }
904
905 if (mEditingExisting && duplicateCount == 1 && mDuplicateId == id) {
906 save();
907 return;
908 }
909
910 new AlertDialog.Builder(this)
911 .setTitle(getString(R.string.save_to_bookmarks_title))
912 .setMessage(getString(R.string.overwrite_bookmark_msg))
913 .setNegativeButton(android.R.string.cancel, null)
914 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
915 public void onClick(DialogInterface dialog, int which) {
916 if (mDuplicateContext == null) {
917 return;
918 }
919 deleteDuplicateBookmark(mDuplicateContext, mDuplicateId);
920 save();
921 }
922 })
923 .show();
924 }
925
The Android Open Source Project0c908882009-03-03 19:32:16 -0800926 /**
Ben Murdoch1794fe22009-09-29 18:14:30 +0100927 * Parse the data entered in the dialog and post a message to update the bookmarks database.
The Android Open Source Project0c908882009-03-03 19:32:16 -0800928 */
929 boolean save() {
Ben Murdoch1794fe22009-09-29 18:14:30 +0100930 createHandler();
931
The Android Open Source Project0c908882009-03-03 19:32:16 -0800932 String title = mTitle.getText().toString().trim();
luxiaoldbe4a622013-07-19 17:14:06 +0800933 String unfilteredUrl = UrlUtils.fixUrl(mAddress.getText().toString());
Ben Murdocheecb4e62010-07-06 16:30:38 +0100934
The Android Open Source Project0c908882009-03-03 19:32:16 -0800935 boolean emptyTitle = title.length() == 0;
936 boolean emptyUrl = unfilteredUrl.trim().length() == 0;
937 Resources r = getResources();
John Reckc8490812010-11-22 14:15:36 -0800938 if (emptyTitle || (emptyUrl && !mEditingFolder)) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800939 if (emptyTitle) {
940 mTitle.setError(r.getText(R.string.bookmark_needs_title));
941 }
942 if (emptyUrl) {
Leon Scroggins III052ce662010-09-13 14:44:16 -0400943 mAddress.setError(r.getText(R.string.bookmark_needs_url));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800944 }
Leon Scroggins III6e3faea2010-09-07 15:22:14 -0400945 return false;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800946 }
Ben Murdochca12cfa2009-11-17 13:57:44 +0000947 String url = unfilteredUrl.trim();
John Reckc8490812010-11-22 14:15:36 -0800948 if (!mEditingFolder) {
949 try {
950 // We allow bookmarks with a javascript: scheme, but these will in most cases
951 // fail URI parsing, so don't try it if that's the kind of bookmark we have.
Ben Murdochca12cfa2009-11-17 13:57:44 +0000952
John Reckc8490812010-11-22 14:15:36 -0800953 if (!url.toLowerCase().startsWith("javascript:")) {
954 URI uriObj = new URI(url);
955 String scheme = uriObj.getScheme();
956 if (!Bookmarks.urlHasAcceptableScheme(url)) {
957 // If the scheme was non-null, let the user know that we
958 // can't save their bookmark. If it was null, we'll assume
959 // they meant http when we parse it in the WebAddress class.
960 if (scheme != null) {
961 mAddress.setError(r.getText(R.string.bookmark_cannot_save_url));
962 return false;
963 }
964 WebAddress address;
965 try {
966 address = new WebAddress(unfilteredUrl);
967 } catch (ParseException e) {
968 throw new URISyntaxException("", "");
969 }
970 if (address.getHost().length() == 0) {
971 throw new URISyntaxException("", "");
972 }
973 url = address.toString();
Ben Murdochca12cfa2009-11-17 13:57:44 +0000974 }
Ben Murdochde353622009-10-12 10:29:00 +0100975 }
John Reckc8490812010-11-22 14:15:36 -0800976 } catch (URISyntaxException e) {
977 mAddress.setError(r.getText(R.string.bookmark_url_not_valid));
978 return false;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800979 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800980 }
Ben Murdochaac7aa62009-09-17 16:57:40 +0100981
Leon Scroggins88d08032010-10-21 15:17:10 -0400982 if (mSaveToHomeScreen) {
983 mEditingExisting = false;
984 }
985
986 boolean urlUnmodified = url.equals(mOriginalUrl);
987
Ben Murdoch1794fe22009-09-29 18:14:30 +0100988 if (mEditingExisting) {
John Reckc8490812010-11-22 14:15:36 -0800989 Long id = mMap.getLong(BrowserContract.Bookmarks._ID);
990 ContentValues values = new ContentValues();
991 values.put(BrowserContract.Bookmarks.TITLE, title);
992 values.put(BrowserContract.Bookmarks.PARENT, mCurrentFolder);
993 if (!mEditingFolder) {
994 values.put(BrowserContract.Bookmarks.URL, url);
995 if (!urlUnmodified) {
996 values.putNull(BrowserContract.Bookmarks.THUMBNAIL);
997 }
998 }
999 if (values.size() > 0) {
1000 new UpdateBookmarkTask(getApplicationContext(), id).execute(values);
1001 }
1002 setResult(RESULT_OK);
Ben Murdoch1794fe22009-09-29 18:14:30 +01001003 } else {
Leon Scroggins88d08032010-10-21 15:17:10 -04001004 Bitmap thumbnail;
1005 Bitmap favicon;
1006 if (urlUnmodified) {
Leon Scrogginsbc922852010-10-22 12:15:27 -04001007 thumbnail = (Bitmap) mMap.getParcelable(
1008 BrowserContract.Bookmarks.THUMBNAIL);
1009 favicon = (Bitmap) mMap.getParcelable(
1010 BrowserContract.Bookmarks.FAVICON);
Leon Scroggins88d08032010-10-21 15:17:10 -04001011 } else {
1012 thumbnail = null;
1013 favicon = null;
1014 }
1015
Ben Murdoch1794fe22009-09-29 18:14:30 +01001016 Bundle bundle = new Bundle();
Leon Scrogginsbc922852010-10-22 12:15:27 -04001017 bundle.putString(BrowserContract.Bookmarks.TITLE, title);
1018 bundle.putString(BrowserContract.Bookmarks.URL, url);
1019 bundle.putParcelable(BrowserContract.Bookmarks.FAVICON, favicon);
Leon Scroggins88d08032010-10-21 15:17:10 -04001020
1021 if (mSaveToHomeScreen) {
1022 if (mTouchIconUrl != null && urlUnmodified) {
1023 Message msg = Message.obtain(mHandler,
1024 TOUCH_ICON_DOWNLOADED);
1025 msg.setData(bundle);
1026 DownloadTouchIcon icon = new DownloadTouchIcon(this, msg,
Leon Scrogginsbc922852010-10-22 12:15:27 -04001027 mMap.getString(USER_AGENT));
Leon Scroggins88d08032010-10-21 15:17:10 -04001028 icon.execute(mTouchIconUrl);
1029 } else {
1030 sendBroadcast(BookmarkUtils.createAddToHomeIntent(this, url,
1031 title, null /*touchIcon*/, favicon));
1032 }
1033 } else {
Leon Scrogginsbc922852010-10-22 12:15:27 -04001034 bundle.putParcelable(BrowserContract.Bookmarks.THUMBNAIL, thumbnail);
1035 bundle.putBoolean(REMOVE_THUMBNAIL, !urlUnmodified);
1036 bundle.putString(TOUCH_ICON_URL, mTouchIconUrl);
Leon Scroggins88d08032010-10-21 15:17:10 -04001037 // Post a message to write to the DB.
1038 Message msg = Message.obtain(mHandler, SAVE_BOOKMARK);
1039 msg.setData(bundle);
1040 // Start a new thread so as to not slow down the UI
1041 Thread t = new Thread(new SaveBookmarkRunnable(getApplicationContext(), msg));
1042 t.start();
1043 }
Ben Murdoch1794fe22009-09-29 18:14:30 +01001044 setResult(RESULT_OK);
Kristian Monsen0a1d8382010-02-01 18:41:07 +00001045 LogTag.logBookmarkAdded(url, "bookmarkview");
The Android Open Source Project0c908882009-03-03 19:32:16 -08001046 }
luxiaoldbe4a622013-07-19 17:14:06 +08001047 finish();
The Android Open Source Project0c908882009-03-03 19:32:16 -08001048 return true;
1049 }
Leon Scroggins162f8352010-10-18 15:02:44 -04001050
John Reck2eec4c32011-05-11 15:55:32 -07001051 @Override
1052 public void onItemSelected(AdapterView<?> parent, View view, int position,
1053 long id) {
1054 if (mAccountSpinner == parent) {
1055 long root = mAccountAdapter.getItem(position).rootFolderId;
1056 if (root != mRootFolder) {
1057 onRootFolderFound(root);
John Recke890c902011-07-11 17:44:43 -07001058 mFolderAdapter.clearRecentFolder();
John Reck2eec4c32011-05-11 15:55:32 -07001059 }
1060 }
1061 }
1062
1063 @Override
1064 public void onNothingSelected(AdapterView<?> parent) {
1065 // Don't care
1066 }
1067
Leon Scroggins162f8352010-10-18 15:02:44 -04001068 /*
1069 * Class used as a proxy for the InputMethodManager to get to mFolderNamer
1070 */
1071 public static class CustomListView extends ListView {
1072 private EditText mEditText;
1073
1074 public void addEditText(EditText editText) {
1075 mEditText = editText;
1076 }
1077
1078 public CustomListView(Context context) {
1079 super(context);
1080 }
1081
1082 public CustomListView(Context context, AttributeSet attrs) {
1083 super(context, attrs);
1084 }
1085
1086 public CustomListView(Context context, AttributeSet attrs, int defStyle) {
1087 super(context, attrs, defStyle);
1088 }
1089
1090 @Override
1091 public boolean checkInputConnectionProxy(View view) {
1092 return view == mEditText;
1093 }
1094 }
John Reck2eec4c32011-05-11 15:55:32 -07001095
John Reck3bf3cfb2011-10-17 18:00:05 -07001096 static class AccountsLoader extends CursorLoader {
John Reck2eec4c32011-05-11 15:55:32 -07001097
1098 static final String[] PROJECTION = new String[] {
1099 Accounts.ACCOUNT_NAME,
1100 Accounts.ACCOUNT_TYPE,
1101 Accounts.ROOT_ID,
1102 };
1103
1104 static final int COLUMN_INDEX_ACCOUNT_NAME = 0;
1105 static final int COLUMN_INDEX_ACCOUNT_TYPE = 1;
1106 static final int COLUMN_INDEX_ROOT_ID = 2;
1107
1108 public AccountsLoader(Context context) {
John Reck1e9815d2011-08-08 17:45:05 -07001109 super(context, Accounts.CONTENT_URI, PROJECTION, null, null, null);
John Reck2eec4c32011-05-11 15:55:32 -07001110 }
1111
1112 }
1113
John Reck9b8cd1e2011-05-25 18:14:01 -07001114 public static class BookmarkAccount {
John Reck2eec4c32011-05-11 15:55:32 -07001115
1116 private String mLabel;
1117 String accountName, accountType;
John Reck9b8cd1e2011-05-25 18:14:01 -07001118 public long rootFolderId;
John Reck2eec4c32011-05-11 15:55:32 -07001119
1120 public BookmarkAccount(Context context, Cursor cursor) {
1121 accountName = cursor.getString(
1122 AccountsLoader.COLUMN_INDEX_ACCOUNT_NAME);
1123 accountType = cursor.getString(
1124 AccountsLoader.COLUMN_INDEX_ACCOUNT_TYPE);
1125 rootFolderId = cursor.getLong(
1126 AccountsLoader.COLUMN_INDEX_ROOT_ID);
1127 mLabel = accountName;
1128 if (TextUtils.isEmpty(mLabel)) {
1129 mLabel = context.getString(R.string.local_bookmarks);
1130 }
1131 }
1132
1133 @Override
1134 public String toString() {
1135 return mLabel;
1136 }
1137 }
1138
1139 static class EditBookmarkInfo {
1140 long id = -1;
1141 long parentId = -1;
1142 String parentTitle;
1143 String title;
1144 String accountName;
1145 String accountType;
1146
1147 long lastUsedId = -1;
1148 String lastUsedTitle;
1149 String lastUsedAccountName;
1150 String lastUsedAccountType;
1151 }
1152
1153 static class EditBookmarkInfoLoader extends AsyncTaskLoader<EditBookmarkInfo> {
1154
1155 private Context mContext;
1156 private Bundle mMap;
1157
1158 public EditBookmarkInfoLoader(Context context, Bundle bundle) {
1159 super(context);
Ben Murdoch914c5592011-08-01 13:58:47 +01001160 mContext = context.getApplicationContext();
John Reck2eec4c32011-05-11 15:55:32 -07001161 mMap = bundle;
1162 }
1163
1164 @Override
1165 public EditBookmarkInfo loadInBackground() {
1166 final ContentResolver cr = mContext.getContentResolver();
1167 EditBookmarkInfo info = new EditBookmarkInfo();
1168 Cursor c = null;
1169
1170 try {
1171 // First, let's lookup the bookmark (check for dupes, get needed info)
1172 String url = mMap.getString(BrowserContract.Bookmarks.URL);
1173 info.id = mMap.getLong(BrowserContract.Bookmarks._ID, -1);
1174 boolean checkForDupe = mMap.getBoolean(CHECK_FOR_DUPE);
1175 if (checkForDupe && info.id == -1 && !TextUtils.isEmpty(url)) {
1176 c = cr.query(BrowserContract.Bookmarks.CONTENT_URI,
1177 new String[] { BrowserContract.Bookmarks._ID},
1178 BrowserContract.Bookmarks.URL + "=?",
1179 new String[] { url }, null);
1180 if (c.getCount() == 1 && c.moveToFirst()) {
1181 info.id = c.getLong(0);
1182 }
1183 c.close();
1184 }
1185 if (info.id != -1) {
1186 c = cr.query(ContentUris.withAppendedId(
1187 BrowserContract.Bookmarks.CONTENT_URI, info.id),
1188 new String[] {
1189 BrowserContract.Bookmarks.PARENT,
1190 BrowserContract.Bookmarks.ACCOUNT_NAME,
1191 BrowserContract.Bookmarks.ACCOUNT_TYPE,
1192 BrowserContract.Bookmarks.TITLE},
1193 null, null, null);
1194 if (c.moveToFirst()) {
1195 info.parentId = c.getLong(0);
1196 info.accountName = c.getString(1);
1197 info.accountType = c.getString(2);
1198 info.title = c.getString(3);
1199 }
1200 c.close();
1201 c = cr.query(ContentUris.withAppendedId(
1202 BrowserContract.Bookmarks.CONTENT_URI, info.parentId),
1203 new String[] {
1204 BrowserContract.Bookmarks.TITLE,},
1205 null, null, null);
1206 if (c.moveToFirst()) {
1207 info.parentTitle = c.getString(0);
1208 }
1209 c.close();
1210 }
1211
1212 // Figure out the last used folder/account
1213 c = cr.query(BrowserContract.Bookmarks.CONTENT_URI,
1214 new String[] {
1215 BrowserContract.Bookmarks.PARENT,
1216 }, null, null,
1217 BrowserContract.Bookmarks.DATE_MODIFIED + " DESC LIMIT 1");
1218 if (c.moveToFirst()) {
1219 long parent = c.getLong(0);
1220 c.close();
1221 c = cr.query(BrowserContract.Bookmarks.CONTENT_URI,
1222 new String[] {
1223 BrowserContract.Bookmarks.TITLE,
1224 BrowserContract.Bookmarks.ACCOUNT_NAME,
1225 BrowserContract.Bookmarks.ACCOUNT_TYPE},
1226 BrowserContract.Bookmarks._ID + "=?", new String[] {
1227 Long.toString(parent)}, null);
1228 if (c.moveToFirst()) {
1229 info.lastUsedId = parent;
1230 info.lastUsedTitle = c.getString(0);
1231 info.lastUsedAccountName = c.getString(1);
1232 info.lastUsedAccountType = c.getString(2);
1233 }
1234 c.close();
1235 }
1236 } finally {
1237 if (c != null) {
1238 c.close();
1239 }
1240 }
1241
1242 return info;
1243 }
1244
1245 @Override
1246 protected void onStartLoading() {
1247 forceLoad();
1248 }
1249
1250 }
1251
The Android Open Source Project0c908882009-03-03 19:32:16 -08001252}