blob: a396ee8394fc3791485c846d655ba97fb97a3a2f [file] [log] [blame]
luxiaoldbe4a622013-07-19 17:14:06 +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
Bijan Amirzada41242f22014-03-21 12:12:18 -070017package com.android.browser;
luxiaoldbe4a622013-07-19 17:14:06 +080018
19import android.app.Activity;
luxiaoldbe4a622013-07-19 17:14:06 +080020import android.app.LoaderManager;
21import android.app.LoaderManager.LoaderCallbacks;
22import android.content.AsyncTaskLoader;
23import android.content.ContentResolver;
24import android.content.ContentUris;
25import android.content.ContentValues;
26import android.content.Context;
27import android.content.CursorLoader;
luxiaoldbe4a622013-07-19 17:14:06 +080028import android.content.Loader;
29import android.content.res.Resources;
30import android.database.Cursor;
31import android.graphics.drawable.Drawable;
32import android.net.Uri;
33import android.os.Bundle;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080034
luxiaoldbe4a622013-07-19 17:14:06 +080035import android.text.TextUtils;
luxiaoldbe4a622013-07-19 17:14:06 +080036import android.view.KeyEvent;
37import android.view.LayoutInflater;
38import android.view.View;
39import android.view.ViewGroup;
40import android.view.Window;
41import android.view.inputmethod.EditorInfo;
42import android.view.inputmethod.InputMethodManager;
43import android.widget.AdapterView;
44import android.widget.AdapterView.OnItemSelectedListener;
45import android.widget.ArrayAdapter;
46import android.widget.CursorAdapter;
47import android.widget.EditText;
48import android.widget.Spinner;
49import android.widget.TextView;
50import android.widget.Toast;
51
Bijan Amirzada41242f22014-03-21 12:12:18 -070052import com.android.browser.R;
53import com.android.browser.addbookmark.FolderSpinner;
54import com.android.browser.addbookmark.FolderSpinnerAdapter;
55import com.android.browser.platformsupport.BrowserContract;
56import com.android.browser.platformsupport.BrowserContract.Accounts;
57import com.android.browser.provider.BrowserProvider2;
58import com.android.browser.reflect.ReflectHelper;
luxiaoldbe4a622013-07-19 17:14:06 +080059
60public class AddBookmarkFolder extends Activity implements View.OnClickListener,
61 TextView.OnEditorActionListener, AdapterView.OnItemClickListener,
62 LoaderManager.LoaderCallbacks<Cursor>, BreadCrumbView.Controller,
63 FolderSpinner.OnSetSelectionListener, OnItemSelectedListener {
64
65 public static final long DEFAULT_FOLDER_ID = -1;
66
67 // Place on an edited bookmark to remove the saved thumbnail
68 public static final String CHECK_FOR_DUPE = "check_for_dupe";
69
70 public static final String BOOKMARK_CURRENT_ID = "bookmark_current_id";
71
72 /* package */static final String EXTRA_EDIT_BOOKMARK = "bookmark";
73
74 /* package */static final String EXTRA_IS_FOLDER = "is_folder";
75
kaiyiz3d7e4d52013-09-17 17:56:27 +080076 private static final int MAX_CRUMBS_SHOWN = 1;
luxiaoldbe4a622013-07-19 17:14:06 +080077
78 private long mOriginalFolder = -1;
79
80 private boolean mIsFolderChanged = false;
81
82 private boolean mIsOtherFolderSelected = false;
83
84 private boolean mIsRecentFolder = false;
85
86 // IDs for the CursorLoaders that are used.
87 private static final int LOADER_ID_ACCOUNTS = 0;
88
89 private static final int LOADER_ID_FOLDER_CONTENTS = 1;
90
91 private static final int LOADER_ID_EDIT_INFO = 2;
92
93 private EditText mTitle;
94
95 private EditText mAddress;
96
97 private TextView mButton;
98
99 private View mCancelButton;
100
101 private Bundle mMap;
102
103 private FolderSpinner mFolder;
104
105 private View mDefaultView;
106
107 private View mFolderSelector;
108
109 private EditText mFolderNamer;
110
111 private View mFolderCancel;
112
113 private boolean mIsFolderNamerShowing;
114
115 private View mFolderNamerHolder;
116
117 private View mAddNewFolder;
118
119 private View mAddSeparator;
120
121 private long mCurrentFolder;
122
123 private FolderAdapter mAdapter;
124
125 private BreadCrumbView mCrumbs;
126
127 private TextView mFakeTitle;
128
129 private View mCrumbHolder;
130
131 private AddBookmarkPage.CustomListView mListView;
132
133 private long mRootFolder;
134
135 private TextView mTopLevelLabel;
136
137 private Drawable mHeaderIcon;
138
139 private View mRemoveLink;
140
141 private View mFakeTitleHolder;
142
143 private FolderSpinnerAdapter mFolderAdapter;
144
145 private Spinner mAccountSpinner;
146
147 private ArrayAdapter<BookmarkAccount> mAccountAdapter;
148
149
150 private static class Folder {
151 String mName;
152
153 long mId;
154
155 Folder(String name, long id) {
156 mName = name;
157 mId = id;
158 }
159 }
160
161 private InputMethodManager getInputMethodManager() {
162 return (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
163 }
164
165 private Uri getUriForFolder(long folder) {
166 BookmarkAccount account = (BookmarkAccount) mAccountSpinner.getSelectedItem();
167 if (folder == mRootFolder && account != null) {
168 return BookmarksLoader.addAccount(BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER,
169 account.mAccountType, account.mAccountName);
170 }
171 return BrowserContract.Bookmarks.buildFolderUri(folder);
172 }
173
174 public static long getIdFromData(Object data) {
175 if (data == null) {
176 return BrowserProvider2.FIXED_ID_ROOT;
177 } else {
178 Folder folder = (Folder) data;
179 return folder.mId;
180 }
181 }
182
183 @Override
184 public void onTop(BreadCrumbView view, int level, Object data) {
185 if (null == data) {
186 return;
187 }
188 Folder folderData = (Folder) data;
189 long folder = folderData.mId;
190 LoaderManager manager = getLoaderManager();
191 CursorLoader loader = (CursorLoader) ((Loader<?>) manager
192 .getLoader(LOADER_ID_FOLDER_CONTENTS));
193 loader.setUri(getUriForFolder(folder));
194 loader.forceLoad();
195 if (mIsFolderNamerShowing) {
196 completeOrCancelFolderNaming(true);
197 }
198 setShowBookmarkIcon(level == 1);
199 }
200
201 /**
202 * Show or hide the icon for bookmarks next to "Bookmarks" in the crumb
203 * view.
204 *
205 * @param show True if the icon should visible, false otherwise.
206 */
207 private void setShowBookmarkIcon(boolean show) {
208 Drawable drawable = show ? mHeaderIcon : null;
209 mTopLevelLabel.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
210 }
211
212 @Override
213 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
214 if (v == mFolderNamer) {
215 if (v.getText().length() > 0) {
216 if (actionId == EditorInfo.IME_NULL) {
217 // Only want to do this once.
218 if (event.getAction() == KeyEvent.ACTION_UP) {
219 completeOrCancelFolderNaming(false);
220 }
221 }
222 }
223 // Steal the key press; otherwise a newline will be added
224 return true;
225 }
226 return false;
227 }
228
229 private void switchToDefaultView(boolean changedFolder) {
230 mFolderSelector.setVisibility(View.GONE);
231 mDefaultView.setVisibility(View.VISIBLE);
232 mCrumbHolder.setVisibility(View.GONE);
233 mFakeTitleHolder.setVisibility(View.VISIBLE);
234 if (changedFolder) {
235 Object data = mCrumbs.getTopData();
236 if (data != null) {
237 Folder folder = (Folder) data;
238 mCurrentFolder = folder.mId;
239 if (mCurrentFolder == mRootFolder) {
240 // The Spinner changed to show "Other folder ..." Change
241 // it back to "Bookmarks", which is position 0 if we are
242 // editing a folder, 1 otherwise.
243 mFolder.setSelectionIgnoringSelectionChange(0);
244 } else {
245 mFolderAdapter.setOtherFolderDisplayText(folder.mName);
246 }
247 }
248 } else {
249 if (mCurrentFolder == mRootFolder) {
250 mFolder.setSelectionIgnoringSelectionChange(0);
251 } else {
252 Object data = mCrumbs.getTopData();
253 if (data != null && ((Folder) data).mId == mCurrentFolder) {
254 // We are showing the correct folder hierarchy. The
255 // folder selector will say "Other folder..." Change it
256 // to say the name of the folder once again.
257 mFolderAdapter.setOtherFolderDisplayText(((Folder) data).mName);
258 } else {
259 // We are not showing the correct folder hierarchy.
260 // Clear the Crumbs and find the proper folder
261 setupTopCrumb();
262 LoaderManager manager = getLoaderManager();
263 manager.restartLoader(LOADER_ID_FOLDER_CONTENTS, null, this);
264
265 }
266 }
267 }
268 }
269
270 @Override
271 public void onClick(View v) {
272 if (v == mButton) {
273 if (mFolderSelector.getVisibility() == View.VISIBLE) {
274 // We are showing the folder selector.
275 if (mIsFolderNamerShowing) {
276 completeOrCancelFolderNaming(false);
277 } else {
278 switchToDefaultView(true);
279 }
280 } else {
281 if (save()) {
282 finish();
283 }
284 }
285 } else if (v == mCancelButton) {
286 if (mIsFolderNamerShowing) {
287 completeOrCancelFolderNaming(true);
288 } else if (mFolderSelector.getVisibility() == View.VISIBLE) {
289 switchToDefaultView(false);
290 } else {
291 finish();
292 }
293 } else if (v == mFolderCancel) {
294 completeOrCancelFolderNaming(true);
295 }
296 }
297
298 private void displayToastForExistingFolder() {
299 Toast.makeText(getApplicationContext(), R.string.duplicated_folder_warning,
300 Toast.LENGTH_LONG).show();
301 }
302
303 @Override
304 public void onSetSelection(long id) {
305 int intId = (int) id;
306 mIsFolderChanged = true;
307 mIsOtherFolderSelected = false;
308 mIsRecentFolder = false;
309 switch (intId) {
310 case FolderSpinnerAdapter.ROOT_FOLDER:
311 mCurrentFolder = mRootFolder;
312 mOriginalFolder = mCurrentFolder;
313 break;
314 case FolderSpinnerAdapter.HOME_SCREEN:
315
316 break;
317 case FolderSpinnerAdapter.OTHER_FOLDER:
318 mIsOtherFolderSelected = true;
319 switchToFolderSelector();
320 break;
321 case FolderSpinnerAdapter.RECENT_FOLDER:
322 mCurrentFolder = mFolderAdapter.recentFolderId();
323 mOriginalFolder = mCurrentFolder;
324 mIsRecentFolder = true;
325 // In case the user decides to select OTHER_FOLDER
326 // and choose a different one, so that we will start from
327 // the correct place.
328 LoaderManager manager = getLoaderManager();
329 manager.restartLoader(LOADER_ID_FOLDER_CONTENTS, null, this);
330 break;
331 default:
332 break;
333 }
334 }
335
336 /**
337 * Finish naming a folder, and close the IME
338 *
339 * @param cancel If true, the new folder is not created. If false, the new
340 * folder is created and the user is taken inside it.
341 */
342 private void completeOrCancelFolderNaming(boolean cancel) {
343 if (!cancel && !TextUtils.isEmpty(mFolderNamer.getText())) {
344 String name = mFolderNamer.getText().toString();
345 long id = addFolderToCurrent(mFolderNamer.getText().toString());
346 descendInto(name, id);
347 }
348 setShowFolderNamer(false);
349 getInputMethodManager().hideSoftInputFromWindow(mListView.getWindowToken(), 0);
350 }
351
352 private long addFolderToCurrent(String name) {
Tarun Nainani7eff6972015-08-29 10:34:40 +0200353 // Add the folder to the database if doesn't already exists
354 if(getIdFromName(name) != -1)
355 return -1;
356
luxiaoldbe4a622013-07-19 17:14:06 +0800357 ContentValues values = new ContentValues();
358 values.put(BrowserContract.Bookmarks.TITLE, name);
359 values.put(BrowserContract.Bookmarks.IS_FOLDER, 1);
360 long currentFolder;
361 Object data = null;
362 if (null != mCrumbs) {
363 data = mCrumbs.getTopData();
364 }
365 if (data != null) {
366 currentFolder = ((Folder) data).mId;
367 } else {
368 currentFolder = mRootFolder;
369 }
370 currentFolder = mCurrentFolder;
371 if (mIsRecentFolder) {
372 values.put(BrowserContract.Bookmarks.PARENT, mCurrentFolder);
373 } else if (!(mIsFolderChanged && mIsOtherFolderSelected) && mOriginalFolder != -1) {
374 values.put(BrowserContract.Bookmarks.PARENT, mOriginalFolder);
375 } else {
376 values.put(BrowserContract.Bookmarks.PARENT, currentFolder);
377 }
378 Uri uri = getContentResolver().insert(BrowserContract.Bookmarks.CONTENT_URI, values);
379 if (uri != null) {
380 return ContentUris.parseId(uri);
381 } else {
382 return -1;
383 }
384 }
385
386 private void switchToFolderSelector() {
387 // Set the list to the top in case it is scrolled.
388 mListView.setSelection(0);
389 mFakeTitleHolder.setVisibility(View.GONE);
390 // mFakeTitle.setVisibility(View.GONE);
391 mDefaultView.setVisibility(View.GONE);
392 mFolderSelector.setVisibility(View.VISIBLE);
393 mCrumbHolder.setVisibility(View.VISIBLE);
394 getInputMethodManager().hideSoftInputFromWindow(mListView.getWindowToken(), 0);
395 }
396
397 private void descendInto(String foldername, long id) {
398 if (id != DEFAULT_FOLDER_ID) {
399 mCrumbs.pushView(foldername, new Folder(foldername, id));
400 mCrumbs.notifyController();
401 } else {
402 Toast.makeText(getApplicationContext(), R.string.duplicated_folder_warning,
403 Toast.LENGTH_LONG).show();
404 }
405 }
406
407 private LoaderCallbacks<EditBookmarkInfo> mEditInfoLoaderCallbacks = new LoaderCallbacks<EditBookmarkInfo>() {
408
409 @Override
410 public void onLoaderReset(Loader<EditBookmarkInfo> loader) {
411 // Don't care
412 }
413
414 @Override
415 public void onLoadFinished(Loader<EditBookmarkInfo> loader, EditBookmarkInfo info) {
416 boolean setAccount = false;
417 // TODO: Detect if lastUsedId is a subfolder of info.id in the
418 // editing folder case. For now, just don't show the last used
419 // folder at all to prevent any chance of the user adding a parent
420 // folder to a child folder
421 if (info.mLastUsedId != -1 && info.mLastUsedId != info.mId) {
422 if (setAccount && info.mLastUsedId != mRootFolder
423 && TextUtils.equals(info.mLastUsedAccountName, info.mAccountName)
424 && TextUtils.equals(info.mLastUsedAccountType, info.mAccountType)) {
425 mFolderAdapter.addRecentFolder(info.mLastUsedId, info.mLastUsedTitle);
426 } else if (!setAccount) {
427 setAccount = true;
428 setAccount(info.mLastUsedAccountName, info.mLastUsedAccountType);
429 if (info.mLastUsedId != mRootFolder) {
430 mFolderAdapter.addRecentFolder(info.mLastUsedId, info.mLastUsedTitle);
431 }
432 }
433 }
434 if (!setAccount) {
435 mAccountSpinner.setSelection(0);
436 }
437 }
438
439 @Override
440 public Loader<EditBookmarkInfo> onCreateLoader(int id, Bundle args) {
441 return new EditBookmarkInfoLoader(AddBookmarkFolder.this, mMap);
442 }
443 };
444
445 void setAccount(String accountName, String accountType) {
446 for (int i = 0; i < mAccountAdapter.getCount(); i++) {
447 BookmarkAccount account = mAccountAdapter.getItem(i);
448 if (TextUtils.equals(account.mAccountName, accountName)
449 && TextUtils.equals(account.mAccountType, accountType)) {
450 mAccountSpinner.setSelection(i);
451 onRootFolderFound(account.rootFolderId);
452 return;
453 }
454 }
455 }
456
457 @Override
458 public Loader<Cursor> onCreateLoader(int id, Bundle args) {
459 String[] projection;
460 switch (id) {
461 case LOADER_ID_ACCOUNTS:
462 return new AccountsLoader(this);
463 case LOADER_ID_FOLDER_CONTENTS:
464 projection = new String[] {
465 BrowserContract.Bookmarks._ID, BrowserContract.Bookmarks.TITLE,
466 BrowserContract.Bookmarks.IS_FOLDER
467 };
468 String where = BrowserContract.Bookmarks.IS_FOLDER + " != 0" + " AND "
469 + BrowserContract.Bookmarks._ID + " != ?";
470 String whereArgs[] = new String[] {
471 Long.toString(mMap.getLong(BrowserContract.Bookmarks._ID))
472 };
473 long currentFolder;
474 Object data = mCrumbs.getTopData();
475 if (data != null) {
476 currentFolder = ((Folder) data).mId;
477 } else {
478 currentFolder = mRootFolder;
479 }
480 return new CursorLoader(this, getUriForFolder(currentFolder), projection, where,
481 whereArgs, BrowserContract.Bookmarks._ID + " ASC");
482 default:
483 throw new AssertionError("Asking for nonexistant loader!");
484 }
485 }
486
487 @Override
488 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
489 switch (loader.getId()) {
490 case LOADER_ID_ACCOUNTS:
491 mAccountAdapter.clear();
492 while (cursor.moveToNext()) {
493 mAccountAdapter.add(new BookmarkAccount(this, cursor));
494 }
495 getLoaderManager().destroyLoader(LOADER_ID_ACCOUNTS);
496 getLoaderManager().restartLoader(LOADER_ID_EDIT_INFO, null,
497 mEditInfoLoaderCallbacks);
498 break;
499 case LOADER_ID_FOLDER_CONTENTS:
500 mAdapter.changeCursor(cursor);
501 break;
502 default:
503 break;
504 }
505 }
506
507 public void onLoaderReset(Loader<Cursor> loader) {
508 switch (loader.getId()) {
509 case LOADER_ID_FOLDER_CONTENTS:
510 mAdapter.changeCursor(null);
511 break;
512 default:
513 break;
514 }
515 }
516
517 /**
518 * Move cursor to the position that has folderToFind as its "_id".
519 *
520 * @param cursor Cursor containing folders in the bookmarks database
521 * @param folderToFind "_id" of the folder to move to.
522 * @param idIndex Index in cursor of "_id"
523 * @throws AssertionError if cursor is empty or there is no row with
524 * folderToFind as its "_id".
525 */
526 void moveCursorToFolder(Cursor cursor, long folderToFind, int idIndex) throws AssertionError {
527 if (!cursor.moveToFirst()) {
528 throw new AssertionError("No folders in the database!");
529 }
530 long folder;
531 do {
532 folder = cursor.getLong(idIndex);
533 } while (folder != folderToFind && cursor.moveToNext());
534 if (cursor.isAfterLast()) {
535 throw new AssertionError("Folder(id=" + folderToFind
536 + ") holding this bookmark does not exist!");
537 }
538 }
539
540 @Override
541 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
542 TextView tv = (TextView) view.findViewById(android.R.id.text1);
543 // Switch to the folder that was clicked on.
544 descendInto(tv.getText().toString(), id);
545 }
546
547 private void setShowFolderNamer(boolean show) {
548 if (show != mIsFolderNamerShowing) {
549 mIsFolderNamerShowing = show;
550 if (show) {
551 // Set the selection to the folder namer so it will be in
552 // view.
553 mListView.addFooterView(mFolderNamerHolder);
554 } else {
555 mListView.removeFooterView(mFolderNamerHolder);
556 }
557 // Refresh the list.
558 mListView.setAdapter(mAdapter);
559 if (show) {
560 mListView.setSelection(mListView.getCount() - 1);
561 }
562 }
563 }
564
565 /**
566 * Shows a list of names of folders.
567 */
568 private class FolderAdapter extends CursorAdapter {
569 public FolderAdapter(Context context) {
570 super(context, null);
571 }
572
573 @Override
574 public void bindView(View view, Context context, Cursor cursor) {
575 ((TextView) view.findViewById(android.R.id.text1)).setText(cursor.getString(cursor
576 .getColumnIndexOrThrow(BrowserContract.Bookmarks.TITLE)));
577 }
578
579 @Override
580 public View newView(Context context, Cursor cursor, ViewGroup parent) {
581 View view = LayoutInflater.from(context).inflate(R.layout.folder_list_item, null);
582 view.setBackgroundDrawable(context.getResources().getDrawable(
583 android.R.drawable.list_selector_background));
584 return view;
585 }
586
587 @Override
588 public boolean isEmpty() {
589 // Do not show the empty view if the user is creating a new folder.
590 return super.isEmpty() && !mIsFolderNamerShowing;
591 }
592 }
593
594 @Override
595 protected void onCreate(Bundle icicle) {
596 super.onCreate(icicle);
597 requestWindowFeature(Window.FEATURE_NO_TITLE);
598
599 mMap = getIntent().getExtras();
600
601 setContentView(R.layout.browser_add_bookmark);
602
603 Window window = getWindow();
604
605 String title = this.getString(R.string.new_folder);
606 mFakeTitle = (TextView) findViewById(R.id.fake_title);
607 mFakeTitleHolder = findViewById(R.id.title_holder);
608 mFakeTitle.setText(this.getString(R.string.new_folder));
609
610 mTitle = (EditText) findViewById(R.id.title);
luxiaoldbe4a622013-07-19 17:14:06 +0800611 BrowserUtils.maxLengthFilter(AddBookmarkFolder.this, mTitle, BrowserUtils.FILENAME_MAX_LENGTH);
612
613 mTitle.setText(title);
614 mAddress = (EditText) findViewById(R.id.address);
615 mAddress.setVisibility(View.GONE);
616 findViewById(R.id.row_address).setVisibility(View.GONE);
617
618 mButton = (TextView) findViewById(R.id.OK);
619 mButton.setOnClickListener(this);
620
621 mCancelButton = findViewById(R.id.cancel);
622 mCancelButton.setOnClickListener(this);
623
624 mFolder = (FolderSpinner) findViewById(R.id.folder);
625 mFolderAdapter = new FolderSpinnerAdapter(this, false);
626 mFolder.setAdapter(mFolderAdapter);
627 mFolder.setOnSetSelectionListener(this);
628
629 mDefaultView = findViewById(R.id.default_view);
630 mFolderSelector = findViewById(R.id.folder_selector);
631
632 mFolderNamerHolder = getLayoutInflater().inflate(R.layout.new_folder_layout, null);
633 mFolderNamer = (EditText) mFolderNamerHolder.findViewById(R.id.folder_namer);
634 mFolderNamer.setOnEditorActionListener(this);
635 mFolderCancel = mFolderNamerHolder.findViewById(R.id.close);
636 mFolderCancel.setOnClickListener(this);
637
638 mAddNewFolder = findViewById(R.id.add_new_folder);
639 mAddNewFolder.setVisibility(View.GONE);
640 mAddSeparator = findViewById(R.id.add_divider);
641 mAddSeparator.setVisibility(View.GONE);
642
643 mCrumbs = (BreadCrumbView) findViewById(R.id.crumbs);
Pankaj Garg634bf432015-07-13 09:54:21 -0700644 //mCrumbs.setUseBackButton(true);
luxiaoldbe4a622013-07-19 17:14:06 +0800645 mCrumbs.setController(this);
Enrico Rosd6efa972014-12-02 19:49:59 -0800646 mHeaderIcon = getResources().getDrawable(R.drawable.ic_deco_folder_normal);
luxiaoldbe4a622013-07-19 17:14:06 +0800647 mCrumbHolder = findViewById(R.id.crumb_holder);
648 mCrumbs.setMaxVisible(MAX_CRUMBS_SHOWN);
649
650 mAdapter = new FolderAdapter(this);
651 mListView = (AddBookmarkPage.CustomListView) findViewById(R.id.list);
652 View empty = findViewById(R.id.empty);
653 mListView.setEmptyView(empty);
654 mListView.setAdapter(mAdapter);
655 mListView.setOnItemClickListener(this);
656 mListView.addEditText(mFolderNamer);
657
658 mAccountAdapter = new ArrayAdapter<BookmarkAccount>(this,
659 android.R.layout.simple_spinner_item);
660 mAccountAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
661 mAccountSpinner = (Spinner) findViewById(R.id.accounts);
662 mAccountSpinner.setAdapter(mAccountAdapter);
663 mAccountSpinner.setOnItemSelectedListener(this);
664
665 if (!window.getDecorView().isInTouchMode()) {
666 mButton.requestFocus();
667 }
668 // getLoaderManager().restartLoader(LOADER_ID_ACCOUNTS, null, this);
669
670 setShowFolderNamer(false);
671 mFolderNamer.setText(R.string.new_folder);
672 mFolderNamer.requestFocus();
673 InputMethodManager imm = getInputMethodManager();
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800674 Object[] params = {mListView};
675 Class[] type = new Class[] {View.class};
676 ReflectHelper.invokeMethod(imm, "focusIn", type, params);
luxiaoldbe4a622013-07-19 17:14:06 +0800677 imm.showSoftInput(mFolderNamer, InputMethodManager.SHOW_IMPLICIT);
678
679 mCurrentFolder = getIntent().getLongExtra(
680 BrowserContract.Bookmarks.PARENT, DEFAULT_FOLDER_ID);
681 mOriginalFolder = mCurrentFolder;
682 if (!(mCurrentFolder == -1 || mCurrentFolder == 1)) {
683 mFolder.setSelectionIgnoringSelectionChange(1);
684 mFolderAdapter.setOtherFolderDisplayText(getNameFromId(mOriginalFolder));
685 }
686
687 getLoaderManager().restartLoader(LOADER_ID_ACCOUNTS, null, this);
688 }
689
690 // get folder title from folder id
691 private String getNameFromId(long mCurrentFolder2) {
692 String title = "";
693 Cursor cursor = null;
694 try {
695 cursor = getApplicationContext().getContentResolver().query(
696 BrowserContract.Bookmarks.CONTENT_URI,
697 new String[] {
698 BrowserContract.Bookmarks.TITLE
699 },
700 BrowserContract.Bookmarks._ID + " = ? AND "
701 + BrowserContract.Bookmarks.IS_DELETED + " = ? AND "
702 + BrowserContract.Bookmarks.IS_FOLDER + " = ? ", new String[] {
703 String.valueOf(mCurrentFolder2), 0 + "", 1 + ""
704 }, null);
705 if (cursor != null && cursor.getCount() != 0) {
706 while (cursor.moveToNext()) {
707 title = cursor.getString(0);
708 }
709 }
Tarun Nainani7eff6972015-08-29 10:34:40 +0200710 } catch (Exception e) {
711 return title;
luxiaoldbe4a622013-07-19 17:14:06 +0800712 } finally {
713 if (cursor != null) {
714 cursor.close();
715 }
716 }
717 return title;
718 }
719
Tarun Nainani7eff6972015-08-29 10:34:40 +0200720 // get folder id from folder title
721 private long getIdFromName(String title) {
722 String titleIdString = "-1";
723 Cursor cursor = null;
724 try {
725 cursor = getApplicationContext().getContentResolver().query(
726 BrowserContract.Bookmarks.CONTENT_URI,
727 new String[] {
728 BrowserContract.Bookmarks._ID
729 },
730 BrowserContract.Bookmarks.TITLE + " = ? AND "
731 + BrowserContract.Bookmarks.IS_DELETED + " = ? AND "
732 + BrowserContract.Bookmarks.IS_FOLDER + " = ? ", new String[] {
733 title, 0 + "", 1 + ""
734 }, null);
735 if (cursor != null && cursor.getCount() != 0) {
736 while (cursor.moveToNext()) {
737 titleIdString = cursor.getString(0);
738 }
739 }
740 } catch (Exception e) {
741 return Long.parseLong(titleIdString);
742 } finally {
743 if (cursor != null) {
744 cursor.close();
745 }
746 }
747 return Long.parseLong(titleIdString);
748 }
749
luxiaoldbe4a622013-07-19 17:14:06 +0800750 private void showRemoveButton() {
751 findViewById(R.id.remove_divider).setVisibility(View.VISIBLE);
752 mRemoveLink = findViewById(R.id.remove);
753 mRemoveLink.setVisibility(View.VISIBLE);
754 mRemoveLink.setOnClickListener(this);
755 }
756
757 // Called once we have determined which folder is the root folder
758 private void onRootFolderFound(long root) {
759 mRootFolder = root;
760 mCurrentFolder = mRootFolder;
761 setupTopCrumb();
762 onCurrentFolderFound();
763 }
764
765 private void setupTopCrumb() {
766 mCrumbs.clear();
767 String name = getString(R.string.bookmarks);
768 mTopLevelLabel = (TextView) mCrumbs.pushView(name, false, new Folder(name, mRootFolder));
769 // To better match the other folders.
770 mTopLevelLabel.setCompoundDrawablePadding(6);
771 }
772
773 private void onCurrentFolderFound() {
774 LoaderManager manager = getLoaderManager();
775 if (mCurrentFolder != mRootFolder) {
776 // Since we're not in the root folder, change the selection to other
777 // folder now. The text will get changed once we select the correct
778 // folder.
779 mFolder.setSelectionIgnoringSelectionChange(1);
780 } else {
781 setShowBookmarkIcon(true);
782 }
783 // Find the contents of the current folder
784 manager.restartLoader(LOADER_ID_FOLDER_CONTENTS, null, this);
785 }
786
787 /**
788 * Parse the data entered in the dialog and post a message to update the
789 * bookmarks database.
790 */
791 private boolean save() {
792 String title = mTitle.getText().toString().trim();
793
794 boolean emptyTitle = title.length() == 0;
795 Resources r = getResources();
796 if (emptyTitle) {
797 mTitle.setError(r.getText(R.string.bookmark_needs_title));
798 return false;
799 }
800
801 long id = addFolderToCurrent(title);
802 if (id == -1) {
803 displayToastForExistingFolder();
804 return false;
805 }
806
807 setResult(RESULT_OK);
808 return true;
809 }
810
811 @Override
812 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
813 if (mAccountSpinner == parent) {
814 long root = mAccountAdapter.getItem(position).rootFolderId;
815 if (root != mRootFolder) {
816 onRootFolderFound(root);
817 mFolderAdapter.clearRecentFolder();
818 }
819 }
820 }
821
822 @Override
823 public void onNothingSelected(AdapterView<?> parent) {
824 // Don't care
825 }
826
827 static class AccountsLoader extends CursorLoader {
828
829 static final String[] PROJECTION = new String[] {
830 Accounts.ACCOUNT_NAME, Accounts.ACCOUNT_TYPE, Accounts.ROOT_ID,
831 };
832
833 static final int COLUMN_INDEX_ACCOUNT_NAME = 0;
834
835 static final int COLUMN_INDEX_ACCOUNT_TYPE = 1;
836
837 static final int COLUMN_INDEX_ROOT_ID = 2;
838
839 public AccountsLoader(Context context) {
840 super(context, Accounts.CONTENT_URI, PROJECTION, null, null, null);
841 }
842
843 }
844
845 public static class BookmarkAccount {
846
847 private String mLabel;
848
849 String mAccountName;
850 String mAccountType;
851
852 public long rootFolderId;
853
854 public BookmarkAccount(Context context, Cursor cursor) {
855 mAccountName = cursor.getString(AccountsLoader.COLUMN_INDEX_ACCOUNT_NAME);
856 mAccountType = cursor.getString(AccountsLoader.COLUMN_INDEX_ACCOUNT_TYPE);
857 rootFolderId = cursor.getLong(AccountsLoader.COLUMN_INDEX_ROOT_ID);
858 mLabel = mAccountName;
859 if (TextUtils.isEmpty(mLabel)) {
860 mLabel = context.getString(R.string.local_bookmarks);
861 }
862 }
863
864 @Override
865 public String toString() {
866 return mLabel;
867 }
868 }
869
870 static class EditBookmarkInfo {
871 long mId = -1;
872
873 long mParentId = -1;
874
875 String mParentTitle;
876
877 String mEBITitle;
878
879 String mAccountName;
880
881 String mAccountType;
882
883 long mLastUsedId = -1;
884
885 String mLastUsedTitle;
886
887 String mLastUsedAccountName;
888
889 String mLastUsedAccountType;
890 }
891
892 static class EditBookmarkInfoLoader extends AsyncTaskLoader<EditBookmarkInfo> {
893
894 private Context mContext;
895
896 private Bundle mMap;
897
898 public EditBookmarkInfoLoader(Context context, Bundle bundle) {
899 super(context);
900 mContext = context.getApplicationContext();
901 mMap = bundle;
902 }
903
904 @Override
905 public EditBookmarkInfo loadInBackground() {
906 final ContentResolver cr = mContext.getContentResolver();
907 EditBookmarkInfo info = new EditBookmarkInfo();
908 Cursor c = null;
909 try {
910 // First, let's lookup the bookmark (check for dupes, get needed
911 // info)
912 String url = mMap.getString(BrowserContract.Bookmarks.URL);
913 info.mId = mMap.getLong(BrowserContract.Bookmarks._ID, -1);
914 boolean checkForDupe = mMap.getBoolean(CHECK_FOR_DUPE);
915 if (checkForDupe && info.mId == -1 && !TextUtils.isEmpty(url)) {
916 c = cr.query(BrowserContract.Bookmarks.CONTENT_URI, new String[] {
917 BrowserContract.Bookmarks._ID
918 }, BrowserContract.Bookmarks.URL + "=?", new String[] {
919 url
920 }, null);
921 if (c.getCount() == 1 && c.moveToFirst()) {
922 info.mId = c.getLong(0);
923 }
924 c.close();
925 }
926 if (info.mId != -1) {
927 c = cr.query(ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI,
928 info.mId), new String[] {
929 BrowserContract.Bookmarks.PARENT,
930 BrowserContract.Bookmarks.ACCOUNT_NAME,
931 BrowserContract.Bookmarks.ACCOUNT_TYPE, BrowserContract.Bookmarks.TITLE
932 }, null, null, null);
933 if (c.moveToFirst()) {
934 info.mParentId = c.getLong(0);
935 info.mAccountName = c.getString(1);
936 info.mAccountType = c.getString(2);
937 info.mEBITitle = c.getString(3);
938 }
939 c.close();
940 c = cr.query(ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI,
941 info.mParentId), new String[] {
942 BrowserContract.Bookmarks.TITLE,
943 }, null, null, null);
944 if (c.moveToFirst()) {
945 info.mParentTitle = c.getString(0);
946 }
947 c.close();
948 }
949
950 // Figure out the last used folder/account
951 c = cr.query(BrowserContract.Bookmarks.CONTENT_URI, new String[] {
952 BrowserContract.Bookmarks.PARENT,
953 }, null, null, BrowserContract.Bookmarks.DATE_MODIFIED + " DESC LIMIT 1");
954 if (c.moveToFirst()) {
955 long parent = c.getLong(0);
956 c.close();
957 c = cr.query(BrowserContract.Bookmarks.CONTENT_URI, new String[] {
958 BrowserContract.Bookmarks.TITLE,
959 BrowserContract.Bookmarks.ACCOUNT_NAME,
960 BrowserContract.Bookmarks.ACCOUNT_TYPE
961 }, BrowserContract.Bookmarks._ID + "=?", new String[] {
962 Long.toString(parent)
963 }, null);
964 if (c.moveToFirst()) {
965 info.mLastUsedId = parent;
966 info.mLastUsedTitle = c.getString(0);
967 info.mLastUsedAccountName = c.getString(1);
968 info.mLastUsedAccountType = c.getString(2);
969 }
970 c.close();
971 }
Tarun Nainani7eff6972015-08-29 10:34:40 +0200972 } catch (Exception e) {
973 return info;
luxiaoldbe4a622013-07-19 17:14:06 +0800974 } finally {
975 if (c != null) {
976 c.close();
977 }
978 }
979 return info;
980 }
981
982 @Override
983 protected void onStartLoading() {
984 forceLoad();
985 }
986 }
987}