OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.chrome.browser.bookmark; |
| 6 |
| 7 import android.Manifest; |
| 8 import android.app.Fragment; |
| 9 import android.app.FragmentManager.OnBackStackChangedListener; |
| 10 import android.app.FragmentTransaction; |
| 11 import android.content.Intent; |
| 12 import android.content.pm.PackageManager; |
| 13 import android.content.res.Configuration; |
| 14 import android.net.Uri; |
| 15 import android.nfc.NfcAdapter; |
| 16 import android.os.Bundle; |
| 17 import android.os.Process; |
| 18 import android.support.v4.app.FragmentActivity; |
| 19 import android.util.Log; |
| 20 import android.view.WindowManager; |
| 21 |
| 22 import org.chromium.base.VisibleForTesting; |
| 23 import org.chromium.base.annotations.SuppressFBWarnings; |
| 24 import org.chromium.base.library_loader.ProcessInitException; |
| 25 import org.chromium.chrome.browser.ChromiumApplication; |
| 26 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils; |
| 27 import org.chromium.ui.UiUtils; |
| 28 import org.chromium.ui.base.DeviceFormFactor; |
| 29 |
| 30 /** |
| 31 * This class provides the adding bookmark UI. It is also required by |
| 32 * android.provider.Browser.saveBookmark |
| 33 */ |
| 34 public class ManageBookmarkActivity extends FragmentActivity { |
| 35 |
| 36 private static final String BOOKMARK_ID_URI_PARAM = "id"; |
| 37 private static final String BOOKMARK_IS_FOLDER_URI_PARAM = "isfolder"; |
| 38 |
| 39 private static final String TAG = "ManageBookmarkActivity"; |
| 40 |
| 41 /* TODO(gb-deprecation): Use android.provider.BrowserContract.Bookmarks.IS_F
OLDER */ |
| 42 public static final String BOOKMARK_INTENT_IS_FOLDER = "folder"; |
| 43 /* TODO(gb-deprecation): Use android.provider.BrowserContract.Bookmarks.TITL
E */ |
| 44 public static final String BOOKMARK_INTENT_TITLE = "title"; |
| 45 /* TODO(gb-deprecation): Use android.provider.BrowserContract.Bookmarks.URL
*/ |
| 46 public static final String BOOKMARK_INTENT_URL = "url"; |
| 47 /* TODO(gb-deprecation): Use android.provider.BrowserContract.Bookmarks._ID
*/ |
| 48 public static final String BOOKMARK_INTENT_ID = "_id"; |
| 49 |
| 50 /** |
| 51 * The tag used when adding the base add/edit bookmark fragment. |
| 52 */ |
| 53 @VisibleForTesting |
| 54 public static final String BASE_ADD_EDIT_FRAGMENT_TAG = "AddEdit"; |
| 55 /** |
| 56 * The tag used when adding the folder selection fragment triggered by the b
ase |
| 57 * add/edit bookmark fragment. |
| 58 */ |
| 59 @VisibleForTesting |
| 60 public static final String BASE_SELECT_FOLDER_FRAGMENT_TAG = "SelectFolder"; |
| 61 /** |
| 62 * The tag used when adding the add new bookmark folder fragment triggered b
y the initial |
| 63 * folder selection fragment. |
| 64 */ |
| 65 @VisibleForTesting |
| 66 public static final String ADD_FOLDER_FRAGMENT_TAG = "AddFolder"; |
| 67 /** |
| 68 * The tag used when adding the folder selection fragment triggered by the a
dd new bookmark |
| 69 * folder fragment. |
| 70 */ |
| 71 protected static final String ADD_FOLDER_SELECT_FOLDER_FRAGMENT_TAG = "AddFo
lderSelectFolder"; |
| 72 |
| 73 /** |
| 74 * Internally used to temporarily disable the back button while performing n
on-cancelable |
| 75 * asynchronous tasks that modify the bookmark model. |
| 76 */ |
| 77 private boolean mIsBackEnabled = true; |
| 78 |
| 79 @Override |
| 80 protected void onCreate(Bundle savedInstanceState) { |
| 81 super.onCreate(savedInstanceState); |
| 82 try { |
| 83 if (getApplication() instanceof ChromiumApplication) { |
| 84 ((ChromiumApplication) getApplication()) |
| 85 .startBrowserProcessesAndLoadLibrariesSync(this, true); |
| 86 } |
| 87 } catch (ProcessInitException e) { |
| 88 Log.e(TAG, "Unable to load native library.", e); |
| 89 ChromiumApplication.reportStartupErrorAndExit(e); |
| 90 return; |
| 91 } |
| 92 if (!DeviceFormFactor.isTablet(this)) { |
| 93 getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_S
TATE_HIDDEN |
| 94 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); |
| 95 } |
| 96 |
| 97 if (savedInstanceState == null) { |
| 98 FragmentTransaction fragmentTransaction = getFragmentManager().begin
Transaction(); |
| 99 fragmentTransaction.add( |
| 100 android.R.id.content, generateBaseFragment(), BASE_ADD_EDIT_
FRAGMENT_TAG); |
| 101 fragmentTransaction.commit(); |
| 102 } else { |
| 103 initializeFragmentState(); |
| 104 } |
| 105 |
| 106 // When adding or removing fragments, ensure the keyboard is hidden if v
isible as the |
| 107 // editing fields are no longer on the screen. |
| 108 getFragmentManager().addOnBackStackChangedListener(new OnBackStackChange
dListener() { |
| 109 @Override |
| 110 public void onBackStackChanged() { |
| 111 UiUtils.hideKeyboard(findViewById(android.R.id.content)); |
| 112 } |
| 113 }); |
| 114 if (checkPermission(Manifest.permission.NFC, Process.myPid(), Process.my
Uid()) |
| 115 == PackageManager.PERMISSION_GRANTED) { |
| 116 NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); |
| 117 if (nfcAdapter != null) nfcAdapter.setNdefPushMessage(null, this); |
| 118 } |
| 119 } |
| 120 |
| 121 @Override |
| 122 public void finish() { |
| 123 super.finish(); |
| 124 // Disables closing animation only for large/xlarge screen because the a
ctivity shows in |
| 125 // fullscreen in other cases and so closing animation doesn't look unnat
ural. |
| 126 if (getResources().getConfiguration().isLayoutSizeAtLeast( |
| 127 Configuration.SCREENLAYOUT_SIZE_LARGE)) { |
| 128 overridePendingTransition(0, 0); |
| 129 } |
| 130 } |
| 131 |
| 132 @Override |
| 133 public void onBackPressed() { |
| 134 if (!mIsBackEnabled) return; |
| 135 if (getFragmentManager().getBackStackEntryCount() == 0) { |
| 136 finish(); |
| 137 } else { |
| 138 getFragmentManager().popBackStackImmediate(); |
| 139 } |
| 140 } |
| 141 |
| 142 /** |
| 143 * Initializes the fragment state after a state restoration. |
| 144 * <p> |
| 145 * Reinitializes all of the event listeners on the fragments as they are not
persisted across |
| 146 * activity recreation (and were referencing the old activity anyway). |
| 147 * <p> |
| 148 * The hidden state of the fragments are also not persisted across activity
changes, so we need |
| 149 * to hide and show the fragments accordingly (since we know that hierarchy
of the fragments |
| 150 * we can do this as a simple nested conditional). |
| 151 */ |
| 152 private void initializeFragmentState() { |
| 153 AddEditBookmarkFragment baseAddEditFragment = (AddEditBookmarkFragment)
getFragmentManager() |
| 154 .findFragmentByTag(BASE_ADD_EDIT_FRAGMENT_TAG); |
| 155 setActionListenerOnAddEdit(baseAddEditFragment); |
| 156 |
| 157 Fragment selectFolderFragment = |
| 158 getFragmentManager().findFragmentByTag(BASE_SELECT_FOLDER_FRAGME
NT_TAG); |
| 159 if (selectFolderFragment != null) { |
| 160 setActionListenerOnFolderSelection( |
| 161 (SelectBookmarkFolderFragment) selectFolderFragment); |
| 162 |
| 163 FragmentTransaction fragmentTransaction = getFragmentManager().begin
Transaction(); |
| 164 fragmentTransaction.hide(baseAddEditFragment); |
| 165 |
| 166 Fragment addFolderFragment = |
| 167 getFragmentManager().findFragmentByTag(ADD_FOLDER_FRAGMENT_T
AG); |
| 168 if (addFolderFragment != null) { |
| 169 fragmentTransaction.hide(selectFolderFragment); |
| 170 setActionListenerOnAddEdit((AddEditBookmarkFragment) addFolderFr
agment); |
| 171 |
| 172 Fragment addFolderSelectFolderFragment = getFragmentManager().fi
ndFragmentByTag( |
| 173 ADD_FOLDER_SELECT_FOLDER_FRAGMENT_TAG); |
| 174 if (addFolderSelectFolderFragment != null) { |
| 175 setActionListenerOnFolderSelection( |
| 176 (SelectBookmarkFolderFragment) addFolderSelectFolder
Fragment); |
| 177 fragmentTransaction.hide(addFolderFragment); |
| 178 fragmentTransaction.show(addFolderSelectFolderFragment); |
| 179 } else { |
| 180 fragmentTransaction.show(addFolderFragment); |
| 181 } |
| 182 } else { |
| 183 fragmentTransaction.show(selectFolderFragment); |
| 184 } |
| 185 fragmentTransaction.commit(); |
| 186 } |
| 187 } |
| 188 |
| 189 /** |
| 190 * Creates the base add/edit bookmark fragment based on the intent passed to
this activity. |
| 191 * |
| 192 * @return The appropriate fragment based on the intent parameters. |
| 193 */ |
| 194 @SuppressFBWarnings("NP_NULL_ON_SOME_PATH") |
| 195 private AddEditBookmarkFragment generateBaseFragment() { |
| 196 if (getIntent() == null) { |
| 197 throw new IllegalArgumentException("intent can not be null"); |
| 198 } |
| 199 Intent intent = getIntent(); |
| 200 Uri intentUri = intent.getData(); |
| 201 |
| 202 Long bookmarkId = null; |
| 203 boolean isFolder = false; |
| 204 AddEditBookmarkFragment addEditFragment; |
| 205 if (intentUri != null && intentUri.getHost().equals("editbookmark")) { |
| 206 isFolder = intentUri.getBooleanQueryParameter(BOOKMARK_IS_FOLDER_URI
_PARAM, false); |
| 207 String bookmarkIdParam = intentUri.getQueryParameter(BOOKMARK_ID_URI
_PARAM); |
| 208 if (bookmarkIdParam != null) bookmarkId = Long.parseLong(bookmarkIdP
aram); |
| 209 addEditFragment = AddEditBookmarkFragment.newEditInstance(isFolder,
bookmarkId); |
| 210 } else { |
| 211 Bundle extras = intent.getExtras(); |
| 212 String url = null; |
| 213 String name = null; |
| 214 if (extras != null) { |
| 215 isFolder = extras.getBoolean(BOOKMARK_INTENT_IS_FOLDER, false); |
| 216 |
| 217 if (extras.containsKey(BOOKMARK_INTENT_TITLE)) { |
| 218 name = extras.getString(BOOKMARK_INTENT_TITLE); |
| 219 } |
| 220 if (extras.containsKey(BOOKMARK_INTENT_URL)) { |
| 221 url = extras.getString(BOOKMARK_INTENT_URL); |
| 222 url = DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(ur
l); |
| 223 } |
| 224 if (extras.containsKey(BOOKMARK_INTENT_ID)) { |
| 225 bookmarkId = extras.getLong(BOOKMARK_INTENT_ID); |
| 226 } |
| 227 } |
| 228 addEditFragment = AddEditBookmarkFragment.newInstance(isFolder, book
markId, name, url); |
| 229 } |
| 230 setActionListenerOnAddEdit(addEditFragment); |
| 231 return addEditFragment; |
| 232 } |
| 233 |
| 234 /** |
| 235 * Creates and sets an action listener on the add/edit bookmark fragment. |
| 236 * @param addEditFragment The fragment that the listener should be attached
to. |
| 237 */ |
| 238 private void setActionListenerOnAddEdit(final AddEditBookmarkFragment addEdi
tFragment) { |
| 239 addEditFragment.setOnActionListener(new AddEditBookmarkFragment.OnAction
Listener() { |
| 240 @Override |
| 241 public void onCancel() { |
| 242 finishAddEdit(); |
| 243 } |
| 244 |
| 245 |
| 246 @Override |
| 247 public void onNodeEdited(long id) { |
| 248 finishAddEdit(); |
| 249 } |
| 250 |
| 251 @Override |
| 252 public void onFolderCreated(long id, String name) { |
| 253 finishAddEdit(); |
| 254 if (getFragmentManager().getBackStackEntryCount() != 0) { |
| 255 ((SelectBookmarkFolderFragment) addEditFragment.getTargetFra
gment()) |
| 256 .executeFolderSelection(id, name); |
| 257 } |
| 258 } |
| 259 |
| 260 @Override |
| 261 public void triggerFolderSelection() { |
| 262 FragmentTransaction fragmentTransaction = getFragmentManager().b
eginTransaction(); |
| 263 |
| 264 boolean isRoot = getFragmentManager().getBackStackEntryCount() =
= 0; |
| 265 SelectBookmarkFolderFragment selectFolder = |
| 266 SelectBookmarkFolderFragment.newInstance( |
| 267 // Only allow the root add/edit bookmark UI to c
reate new bookmark |
| 268 // folders during selection. |
| 269 isRoot, |
| 270 addEditFragment.getParentFolderId(), |
| 271 addEditFragment.isFolder()); |
| 272 selectFolder.setTargetFragment(addEditFragment, 0); |
| 273 setActionListenerOnFolderSelection(selectFolder); |
| 274 |
| 275 String tag = isRoot ? BASE_SELECT_FOLDER_FRAGMENT_TAG |
| 276 : ADD_FOLDER_SELECT_FOLDER_FRAGMENT_TAG; |
| 277 fragmentTransaction.add(android.R.id.content, selectFolder, tag)
; |
| 278 fragmentTransaction.hide(addEditFragment); |
| 279 fragmentTransaction.addToBackStack(null); |
| 280 fragmentTransaction.commit(); |
| 281 } |
| 282 |
| 283 @Override |
| 284 public void onRemove() { |
| 285 finishAddEdit(); |
| 286 } |
| 287 |
| 288 @Override |
| 289 public void setBackEnabled(boolean enabled) { |
| 290 mIsBackEnabled = enabled; |
| 291 } |
| 292 |
| 293 private void finishAddEdit() { |
| 294 if (getFragmentManager().getBackStackEntryCount() == 0) { |
| 295 finish(); |
| 296 } else { |
| 297 getFragmentManager().popBackStackImmediate(); |
| 298 } |
| 299 } |
| 300 }); |
| 301 } |
| 302 |
| 303 /** |
| 304 * Creates and sets an action listener on the bookmark folder selection frag
ment. |
| 305 * @param selectFolder The fragment that the listener should be attached to. |
| 306 */ |
| 307 private void setActionListenerOnFolderSelection( |
| 308 final SelectBookmarkFolderFragment selectFolder) { |
| 309 selectFolder.setOnActionListener(new SelectBookmarkFolderFragment.OnActi
onListener() { |
| 310 @Override |
| 311 public void triggerNewFolderCreation(long selectedFolderId, String s
electedFolderName) { |
| 312 newFolder(selectFolder, selectedFolderId, selectedFolderName); |
| 313 } |
| 314 }); |
| 315 } |
| 316 |
| 317 /** |
| 318 * Create and display the fragment for creating a new bookmark folder. |
| 319 * @param triggeringFragment The fragment that requested the new folder frag
ment to be shown. |
| 320 * @param parentFolderId The ID of the bookmark folder to used as the defaul
t parent of the |
| 321 * folder. |
| 322 * @param parentName The name of the bookmark folder to be used at the defau
lt parent. |
| 323 */ |
| 324 private void newFolder(Fragment triggeringFragment, long parentFolderId, Str
ing parentName) { |
| 325 AddEditBookmarkFragment newFolderFragment = |
| 326 AddEditBookmarkFragment.newAddNewFolderInstance(parentFolderId,
parentName); |
| 327 newFolderFragment.setTargetFragment(triggeringFragment, 0); |
| 328 setActionListenerOnAddEdit(newFolderFragment); |
| 329 getFragmentManager().beginTransaction() |
| 330 .hide(triggeringFragment) |
| 331 .add(android.R.id.content, newFolderFragment, ADD_FOLDER_FRAGMEN
T_TAG) |
| 332 .addToBackStack(null) |
| 333 .commit(); |
| 334 } |
| 335 } |
OLD | NEW |