Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4057)

Unified Diff: chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..62950c4d704c274cf93a86ba98a48b55471e3de3
--- /dev/null
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java
@@ -0,0 +1,648 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.enhancedbookmarks;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.os.Build;
+import android.preference.PreferenceManager;
+import android.support.v4.widget.DrawerLayout;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ViewSwitcher;
+
+import com.google.android.apps.chrome.R;
+
+import org.chromium.base.ObserverList;
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.chrome.browser.BookmarksBridge.BookmarkItem;
+import org.chromium.chrome.browser.BookmarksBridge.BookmarkModelObserver;
+import org.chromium.chrome.browser.UrlConstants;
+import org.chromium.chrome.browser.enhanced_bookmarks.EnhancedBookmarksBridge.FiltersObserver;
+import org.chromium.chrome.browser.enhanced_bookmarks.EnhancedBookmarksModel;
+import org.chromium.chrome.browser.enhanced_bookmarks.LaunchLocation;
+import org.chromium.chrome.browser.ntp.NewTabPageUma;
+import org.chromium.chrome.browser.partnerbookmarks.PartnerBookmarksShim;
+import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarManageable;
+import org.chromium.components.bookmarks.BookmarkId;
+import org.chromium.ui.base.DeviceFormFactor;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * The new bookmark manager that is planned to replace the existing bookmark manager. It holds all
+ * views and shared logics between tablet and phone. For tablet/phone specific logics, see
+ * {@link EnhancedBookmarkActivity} (phone) and {@link EnhancedBookmarkPage} (tablet).
+ */
+public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate {
+ private static final String PREF_LAST_USED_URL = "enhanced_bookmark_last_used_url";
+ static final String PREF_WAS_IN_LIST_MODE = "enhanced_bookmark_list_mode_choice";
+ // TODO(ianwen): upstream these metrics upstream.
+ // UI modes for bookmarks presentation. Default option is grid mode.
+ static final int DEFAULT_MODE = 0;
+ static final int LIST_MODE = 1;
+ static final int GRID_MODE = 2;
+
+ private Activity mActivity;
+ private ViewGroup mMainView;
+ private EnhancedBookmarksModel mEnhancedBookmarksModel;
+ private EnhancedBookmarkUndoController mUndoController;
+ private final ObserverList<EnhancedBookmarkUIObserver> mUIObservers =
+ new ObserverList<EnhancedBookmarkUIObserver>();
+ private Set<BookmarkId> mSelectedBookmarks = new HashSet<>();
+ private boolean mListModeEnabled;
+ private EnhancedBookmarkStateChangeListener mUrlChangeListener;
+ private EnhancedBookmarkContentView mContentView;
+ private EnhancedBookmarkSearchView mSearchView;
+ private ViewSwitcher mViewSwitcher;
+ private DrawerLayout mDrawer;
+ private EnhancedBookmarkDrawerListView mDrawerListView;
+ private final Stack<UIState> mStateStack = new Stack<>();
+
+ private final BookmarkModelObserver mBookmarkModelObserver = new BookmarkModelObserver() {
+ @Override
+ public void bookmarkNodeRemoved(BookmarkItem parent, int oldIndex, BookmarkItem node) {
+ // If the folder is removed in folder mode, show the parent folder or falls back to all
+ // bookmarks mode.
+ if (getCurrentState() == STATE_FOLDER
+ && node.getId().equals(mStateStack.peek().mFolder)) {
+ if (mEnhancedBookmarksModel.getTopLevelFolderIDs(true, true).contains(
+ node.getId())) {
+ openAllBookmarks();
+ } else {
+ openFolder(parent.getId());
+ }
+ }
+ clearSelection();
+ }
+
+ @Override
+ public void bookmarkNodeMoved(BookmarkItem oldParent, int oldIndex, BookmarkItem newParent,
+ int newIndex) {
+ clearSelection();
+ }
+
+ @Override
+ public void bookmarkModelLoaded() {
+ initializeIfBookmarkModelLoaded();
+ }
+
+ @Override
+ public void bookmarkModelChanged() {
+ // If the folder no longer exists in folder mode, we need to fall back. Relying on the
+ // default behavior by setting the folder mode again.
+ if (getCurrentState() == STATE_FOLDER) {
+ setState(mStateStack.peek());
+ }
+ clearSelection();
+ }
+ };
+
+ private final FiltersObserver mFiltersObserver = new FiltersObserver() {
+ @Override
+ public void onFiltersChanged() {
+ // if the current selected filter was removed, we need to fall back. Relying on the
+ // default behavior by setting the filter mode again.
+ if (getCurrentState() == STATE_FILTER) {
+ setState(mStateStack.peek());
+ }
+ }
+ };
+
+ /**
+ * Creates an instance of {@link EnhancedBookmarkManager}. It also initializes resources,
+ * bookmark models and jni bridges.
+ * @param activity The activity context to use.
+ */
+ public EnhancedBookmarkManager(Activity activity) {
+ mActivity = activity;
+ mEnhancedBookmarksModel = new EnhancedBookmarksModel();
+ mMainView = (ViewGroup) mActivity.getLayoutInflater().inflate(R.layout.eb_main, null);
+ mDrawer = (DrawerLayout) mMainView.findViewById(R.id.eb_drawer_layout);
+ mDrawerListView = (EnhancedBookmarkDrawerListView) mMainView.findViewById(
+ R.id.eb_drawer_list);
+ mContentView = (EnhancedBookmarkContentView) mMainView.findViewById(R.id.eb_content_view);
+ mViewSwitcher = (ViewSwitcher) mMainView.findViewById(R.id.eb_view_switcher);
+ mUndoController = new EnhancedBookmarkUndoController(activity, mEnhancedBookmarksModel,
+ ((SnackbarManageable) activity).getSnackbarManager());
+ mSearchView = (EnhancedBookmarkSearchView) getView().findViewById(R.id.eb_search_view);
+ mEnhancedBookmarksModel.addModelObserver(mBookmarkModelObserver);
+ initializeIfBookmarkModelLoaded();
+
+ // Load partner bookmarks explicitly. We load partner bookmarks in the deferred startup
+ // code, but that might be executed much later. Especially on L, showing loading
+ // progress bar blocks that so it won't be loaded. http://crbug.com/429383
+ PartnerBookmarksShim.kickOffReading(activity);
+ }
+
+ /**
+ * Destroys and cleans up itself. This must be called after done using this class.
+ */
+ public void destroy() {
+ for (EnhancedBookmarkUIObserver observer : mUIObservers) {
+ observer.onDestroy();
+ }
+ assert mUIObservers.size() == 0;
+
+ if (mUndoController != null) {
+ mUndoController.destroy();
+ mUndoController = null;
+ }
+ mEnhancedBookmarksModel.removeModelObserver(mBookmarkModelObserver);
+ mEnhancedBookmarksModel.removeFiltersObserver(mFiltersObserver);
+ mEnhancedBookmarksModel.destroy();
+ mEnhancedBookmarksModel = null;
+ }
+
+ /**
+ * Called when the user presses the back key. This is only going to be called on Phone.
+ * @return True if manager handles this event, false if it decides to ignore.
+ */
+ public boolean onBackPressed() {
+ if (doesDrawerExist()) {
+ if (mDrawer.isDrawerVisible(Gravity.START)) {
+ mDrawer.closeDrawer(Gravity.START);
+ return true;
+ }
+ }
+
+ if (mContentView.onBackPressed()) return true;
+
+ if (!mStateStack.empty()) {
+ mStateStack.pop();
+ if (!mStateStack.empty()) {
+ setState(mStateStack.pop());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public View getView() {
+ return mMainView;
+ }
+
+ /**
+ * Sets the listener that reacts upon the change of the UI state of bookmark manager.
+ */
+ public void setUrlChangeListener(EnhancedBookmarkStateChangeListener urlListner) {
+ mUrlChangeListener = urlListner;
+ }
+
+ /**
+ * @return Current URL representing the UI state of bookmark manager. If no state has been shown
+ * yet in this session, on phone return last used state stored in preference; on tablet
+ * return the url previously set by {@link #updateForUrl(String)}.
+ */
+ public String getCurrentUrl() {
+ if (mStateStack.isEmpty()) return null;
+ return mStateStack.peek().mUrl;
+ }
+
+ /**
+ * Updates UI based on the new URL on tablet. If the bookmark model is not loaded yet, creates a
+ * temporary loading state carrying this url. This method is supposed to align with
+ * {@link EnhancedBookmarkPage#updateForUrl(String)}
+ * <p>
+ * @param url The url to navigate to.
+ */
+ public void updateForUrl(String url) {
+ if (mEnhancedBookmarksModel != null && mEnhancedBookmarksModel.isBookmarkModelLoaded()) {
+ setState(UIState.createStateFromUrl(url, mEnhancedBookmarksModel));
+ } else {
+ // Note this does not guarantee to update the UI, as at this time the onCreateView()
+ // might not has even been called yet.
+ setState(UIState.createLoadingState(url));
+ }
+ }
+
+ /**
+ * Initialization method that has 3 different behaviors based on whether bookmark model is
+ * loaded. If the bookmark model is not loaded yet, it pushes a loading state to backstack which
+ * contains the url from preference. If the model is loaded and the backstack is empty, it
+ * creates a state by fetching the last visited bookmark url stored in preference. If the
+ * bookmark model is loaded but backstack contains a pending loading state, it creates a new
+ * state by getting the url of the loading state and replace the previous loading state with the
+ * new normal state.
+ */
+ private void initializeIfBookmarkModelLoaded() {
+ if (mEnhancedBookmarksModel.isBookmarkModelLoaded()) {
+ mEnhancedBookmarksModel.addFiltersObserver(mFiltersObserver);
+ mSearchView.onEnhancedBookmarkDelegateInitialized(this);
+ mDrawerListView.onEnhancedBookmarkDelegateInitialized(this);
+ mContentView.onEnhancedBookmarkDelegateInitialized(this);
+ if (mStateStack.isEmpty()) {
+ setState(UIState.createStateFromUrl(getUrlFromPreference(),
+ mEnhancedBookmarksModel));
+ } else if (mStateStack.peek().mState == STATE_LOADING) {
+ String url = mStateStack.pop().mUrl;
+ setState(UIState.createStateFromUrl(url, mEnhancedBookmarksModel));
+ }
+ // Restore the previous view mode selection saved in preference.
+ initListModeOptionTo(getListModePreference());
+ } else {
+ mContentView.showLoadingUi();
+ mDrawerListView.showLoadingUi();
+ mContentView.showLoadingUi();
+ if (mStateStack.isEmpty() || mStateStack.peek().mState != STATE_LOADING) {
+ setState(UIState.createLoadingState(getUrlFromPreference()));
+ } else if (!mStateStack.isEmpty()) {
+ // Refresh the UI. This is needed because on tablet, updateForUrl might set up
+ // loading state too early and at that time all UI components are not created yet.
+ // Therefore we need to set the previous loading state once again to trigger all UI
+ // updates.
+ setState(mStateStack.pop());
+ }
+ }
+ }
+
+ /**
+ * Saves url to preference. Note this method should be used after the main view is attached to
+ * an activity.
+ */
+ private void saveUrlToPreference(String url) {
+ PreferenceManager.getDefaultSharedPreferences(mActivity).edit()
+ .putString(PREF_LAST_USED_URL, url).apply();
+ }
+
+ /**
+ * Fetches url to preference. Note this method should be used after the main view is attached to
+ * an activity.
+ */
+ private String getUrlFromPreference() {
+ return PreferenceManager.getDefaultSharedPreferences(mActivity).getString(
+ PREF_LAST_USED_URL, UrlConstants.BOOKMARKS_URL);
+ }
+
+ private void saveListModePreference() {
+ PreferenceManager.getDefaultSharedPreferences(mActivity).edit()
+ .putInt(PREF_WAS_IN_LIST_MODE, mListModeEnabled ? LIST_MODE : GRID_MODE).apply();
+ }
+
+ private boolean getListModePreference() {
+ int mode = PreferenceManager.getDefaultSharedPreferences(mActivity).getInt(
+ PREF_WAS_IN_LIST_MODE, DEFAULT_MODE);
+ return mode == LIST_MODE ? true : false;
+ }
+
+ private void initListModeOptionTo(boolean isListModeEnabled) {
+ mListModeEnabled = isListModeEnabled;
+ for (EnhancedBookmarkUIObserver observer: mUIObservers) {
+ observer.onListModeChange(isListModeEnabled);
+ }
+ // Every time the enhanced bookmark manager launches or the user clicks the list-mode
+ // toggle, we record the list view state.
+ int listViewstate = PreferenceManager.getDefaultSharedPreferences(getView().getContext())
+ .getInt(EnhancedBookmarkManager.PREF_WAS_IN_LIST_MODE,
+ EnhancedBookmarkManager.DEFAULT_MODE);
+ RecordHistogram.recordEnumeratedHistogram("EnhancedBookmarks.ViewMode", listViewstate, 3);
+ }
+
+ /**
+ * This is the ultimate internal method that updates UI and controls backstack. And it is the
+ * only method that pushes states to {@link #mStateStack}.
+ * <p>
+ * If the given state is not valid, all_bookmark state will be shown. Afterwards, this method
+ * checks the current state: if currently in loading state, it pops it out and adds the new
+ * state to the back stack. It also notifies the {@link #mUrlChangeListener} (if any) that the
+ * url has changed.
+ * <p>
+ * Also note that even if we store states to {@link #mStateStack}, on tablet the back navigation
+ * and back button are not controlled by the manager: the tab handles back key and backstack
+ * navigation.
+ */
+ private void setState(UIState state) {
+ if (!state.isValid(mEnhancedBookmarksModel)) {
+ state = UIState.createAllBookmarksState(mEnhancedBookmarksModel);
+ }
+ if (!mStateStack.isEmpty()) {
+ if (mStateStack.peek().equals(state)) return;
+ if (mStateStack.peek().mState == STATE_LOADING) {
+ mStateStack.pop();
+ }
+ }
+ mStateStack.push(state);
+ if (state.mState != STATE_LOADING) {
+ // Loading state may be pushed to the stack but should never be stored in preferences.
+ saveUrlToPreference(state.mUrl);
+ // If a loading state is replaced by another loading state, do not notify this change.
+ if (mUrlChangeListener != null) mUrlChangeListener.onBookmarkUIStateChange(state.mUrl);
+ }
+
+ clearSelection();
+
+ for (EnhancedBookmarkUIObserver observer : mUIObservers) {
+ notifyStateChange(observer);
+ }
+ }
+
+ // EnhancedBookmarkDelegate implementations.
+
+ @Override
+ public void openFolder(BookmarkId folder) {
+ closeSearchUI();
+ setState(UIState.createFolderState(folder, mEnhancedBookmarksModel));
+ }
+
+ @Override
+ public void openFilter(String filter) {
+ closeSearchUI();
+ setState(UIState.createFilterState(filter, mEnhancedBookmarksModel));
+ }
+
+ @Override
+ public void openAllBookmarks() {
+ closeSearchUI();
+ setState(UIState.createAllBookmarksState(mEnhancedBookmarksModel));
+ }
+
+ @Override
+ public void clearSelection() {
+ mSelectedBookmarks.clear();
+ for (EnhancedBookmarkUIObserver observer : mUIObservers) {
+ observer.onSelectionStateChange(new ArrayList<BookmarkId>(mSelectedBookmarks));
+ }
+ }
+
+ @Override
+ public boolean toggleSelectionForBookmark(BookmarkId bookmark) {
+ if (!mEnhancedBookmarksModel.getBookmarkById(bookmark).isEditable()) return false;
+
+ if (mSelectedBookmarks.contains(bookmark)) mSelectedBookmarks.remove(bookmark);
+ else mSelectedBookmarks.add(bookmark);
+ for (EnhancedBookmarkUIObserver observer : mUIObservers) {
+ observer.onSelectionStateChange(new ArrayList<BookmarkId>(mSelectedBookmarks));
+ }
+
+ return isBookmarkSelected(bookmark);
+ }
+
+ @Override
+ public boolean isBookmarkSelected(BookmarkId bookmark) {
+ return mSelectedBookmarks.contains(bookmark);
+ }
+
+ @Override
+ public boolean isSelectionEnabled() {
+ return !mSelectedBookmarks.isEmpty();
+ }
+
+ @Override
+ public List<BookmarkId> getSelectedBookmarks() {
+ return new ArrayList<BookmarkId>(mSelectedBookmarks);
+ }
+
+ @Override
+ public void setListModeEnabled(boolean isListModeEnabled) {
+ initListModeOptionTo(isListModeEnabled);
+ saveListModePreference();
+ }
+
+ @Override
+ public boolean isListModeEnabled() {
+ return mListModeEnabled;
+ }
+
+ @Override
+ public void notifyStateChange(EnhancedBookmarkUIObserver observer) {
+ int state = getCurrentState();
+ switch (state) {
+ case STATE_ALL_BOOKMARKS:
+ observer.onAllBookmarksStateSet();
+ break;
+ case STATE_FOLDER:
+ observer.onFolderStateSet(mStateStack.peek().mFolder);
+ break;
+ case STATE_FILTER:
+ observer.onFilterStateSet(mStateStack.peek().mFilter);
+ break;
+ case STATE_LOADING:
+ // In loading state, onEnhancedBookmarkDelegateInitialized() is not called for all
+ // UIObservers, which means that there will be no observers at the time. Do nothing.
+ assert mUIObservers.isEmpty();
+ break;
+ default:
+ assert false : "State not valid";
+ break;
+ }
+ }
+
+ @Override
+ public boolean doesDrawerExist() {
+ return mDrawer != null;
+ }
+
+ @Override
+ public void closeDrawer() {
+ if (!doesDrawerExist()) return;
+
+ mDrawer.closeDrawer(Gravity.START);
+ }
+
+ @Override
+ public DrawerLayout getDrawerLayout() {
+ return mDrawer;
+ }
+
+ @Override
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public void startDetailActivity(BookmarkId bookmarkId, View view) {
+ Intent intent = new Intent(mActivity, EnhancedBookmarkDetailActivity.class);
+ intent.putExtra(EnhancedBookmarkDetailActivity.INTENT_BOOKMARK_ID, bookmarkId.toString());
+ // Shared element animation is disabled on tablet because of bad quality.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || view == null
+ || DeviceFormFactor.isTablet(mActivity)) {
+ mActivity.startActivity(intent);
+ } else {
+ ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, view,
+ mActivity.getString(R.string.enhanced_bookmark_detail_transition_name));
+ mActivity.startActivity(intent, options.toBundle());
+ }
+ }
+
+ @Override
+ public void openBookmark(BookmarkId bookmark, int launchLocation) {
+ clearSelection();
+ NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_BOOKMARK);
+ RecordHistogram.recordEnumeratedHistogram("Stars.LaunchLocation", launchLocation,
+ LaunchLocation.COUNT);
+ EnhancedBookmarkUtils.openBookmark(mActivity,
+ mEnhancedBookmarksModel.getBookmarkById(bookmark).getUrl());
+ finishActivityOnPhone();
+ }
+
+ @Override
+ public void openSearchUI() {
+ // Give search view focus, because it needs to handle back key event.
+ mViewSwitcher.showNext();
+ }
+
+ @Override
+ public void closeSearchUI() {
+ if (mSearchView.getVisibility() != View.VISIBLE) return;
+ mViewSwitcher.showPrevious();
+ }
+
+ @Override
+ public void finishActivityOnPhone() {
+ Activity activity = mActivity;
+ if (activity instanceof EnhancedBookmarkActivity) {
+ activity.finish();
+ }
+ }
+
+ @Override
+ public void addUIObserver(EnhancedBookmarkUIObserver observer) {
+ mUIObservers.addObserver(observer);
+ }
+
+ @Override
+ public void removeUIObserver(EnhancedBookmarkUIObserver observer) {
+ mUIObservers.removeObserver(observer);
+ }
+
+ @Override
+ public EnhancedBookmarksModel getModel() {
+ return mEnhancedBookmarksModel;
+ }
+
+ @Override
+ public int getCurrentState() {
+ if (mStateStack.isEmpty()) return STATE_LOADING;
+ return mStateStack.peek().mState;
+ }
+
+ /**
+ * Internal state that represents a url. Note every state needs to have a _valid_ url. For
+ * loading state, {@link #mUrl} indicates the target to open after the bookmark model is loaded.
+ */
+ private static class UIState {
+ private static final String TAG = "UIState";
+ private static final String URL_CHARSET = "UTF-8";
+ /**
+ * One of the four states:
+ * {@link EnhancedBookmarkDelegate#STATE_ALL_BOOKMARKS},
+ * {@link EnhancedBookmarkDelegate#STATE_FILTER},
+ * {@link EnhancedBookmarkDelegate#STATE_FOLDER},
+ * {@link EnhancedBookmarkDelegate#STATE_LOADING},
+ */
+ int mState;
+ String mUrl;
+ BookmarkId mFolder;
+ String mFilter;
+
+ static UIState createLoadingState(String url) {
+ UIState state = new UIState();
+ state.mUrl = url;
+ state.mState = STATE_LOADING;
+ return state;
+ }
+
+ static UIState createAllBookmarksState(EnhancedBookmarksModel bookmarkModel) {
+ return createStateFromUrl(UrlConstants.BOOKMARKS_URL, bookmarkModel);
+ }
+
+ static UIState createFolderState(BookmarkId folder, EnhancedBookmarksModel bookmarkModel) {
+ return createStateFromUrl(UrlConstants.BOOKMARKS_FOLDER_URL + folder.toString(),
+ bookmarkModel);
+ }
+
+ static UIState createFilterState(String filter, EnhancedBookmarksModel bookmarkModel) {
+ return createStateFromUrl(encodeUrl(UrlConstants.BOOKMARKS_FILTER_URL, filter),
+ bookmarkModel);
+ }
+
+ /**
+ * @return A state corresponding to the url. If the url is not valid, return all_bookmarks.
+ */
+ static UIState createStateFromUrl(String url, EnhancedBookmarksModel bookmarkModel) {
+ UIState state = new UIState();
+ state.mUrl = url;
+ if (url.equals(UrlConstants.BOOKMARKS_URL)) {
+ state.mState = STATE_ALL_BOOKMARKS;
+ } else if (url.startsWith(UrlConstants.BOOKMARKS_FILTER_URL)) {
+ String suffix = decodeSuffix(url, UrlConstants.BOOKMARKS_FILTER_URL);
+ if (!suffix.isEmpty()) {
+ state.mState = STATE_FILTER;
+ state.mFilter = suffix;
+ }
+ } else if (url.startsWith(UrlConstants.BOOKMARKS_FOLDER_URL)) {
+ String suffix = decodeSuffix(url, UrlConstants.BOOKMARKS_FOLDER_URL);
+ if (!suffix.isEmpty()) {
+ state.mFolder = BookmarkId.getBookmarkIdFromString(suffix);
+ state.mState = STATE_FOLDER;
+ }
+ }
+
+ if (!state.isValid(bookmarkModel)) {
+ state.mState = STATE_ALL_BOOKMARKS;
+ state.mUrl = UrlConstants.BOOKMARKS_URL;
+ }
+
+ return state;
+ }
+
+ /**
+ * @return Whether this state is valid.
+ */
+ boolean isValid(EnhancedBookmarksModel bookmarkModel) {
+ if (mUrl == null) return false;
+ if (mState == STATE_FOLDER) {
+ if (mFolder == null) return false;
+
+ return bookmarkModel.doesBookmarkExist(mFolder)
+ && !mFolder.equals(bookmarkModel.getRootFolderId());
+ }
+ if (mState == STATE_FILTER) {
+ if (mFilter == null) return false;
+ else return bookmarkModel.getFilters().contains(mFilter);
+ }
+
+ return true;
+ }
+
+ static String decodeSuffix(String url, String prefix) {
+ String suffix = url.substring(prefix.length());
+ try {
+ suffix = URLDecoder.decode(suffix, URL_CHARSET);
+ } catch (UnsupportedEncodingException e) {
+ Log.w(TAG, "Bookmark URL parsing failed. " + URL_CHARSET + " not supported.");
+ }
+ return suffix;
+ }
+
+ static String encodeUrl(String prefix, String suffix) {
+ try {
+ suffix = URLEncoder.encode(suffix, URL_CHARSET);
+ } catch (UnsupportedEncodingException e) {
+ Log.w(TAG, "Bookmark URL parsing failed. " + URL_CHARSET + " not supported.");
+ }
+ return prefix + suffix;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * mUrl.hashCode() + mState;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof UIState)) return false;
+ UIState other = (UIState) obj;
+ return mState == other.mState && mUrl.equals(other.mUrl);
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698