Index: chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java |
index 8d7a6cfb6bb1bd8bf75d35dd64ebc659a464c2c8..c62c332962cb118df83993ea3e52bc6ab439ad4b 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java |
@@ -4,24 +4,36 @@ |
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.R; |
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; |
+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.enhanced_bookmarks.ViewMode; |
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; |
@@ -39,6 +51,7 @@ import java.util.Stack; |
*/ |
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"; |
private Activity mActivity; |
private ViewGroup mMainView; |
@@ -47,8 +60,11 @@ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { |
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<>(); |
@@ -58,7 +74,7 @@ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { |
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() == UIState.STATE_FOLDER |
+ if (getCurrentState() == STATE_FOLDER |
&& node.getId().equals(mStateStack.peek().mFolder)) { |
if (mEnhancedBookmarksModel.getTopLevelFolderIDs(true, true).contains( |
node.getId())) { |
@@ -85,13 +101,24 @@ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { |
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() == UIState.STATE_FOLDER) { |
+ 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. |
@@ -105,9 +132,11 @@ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { |
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()); |
- mEnhancedBookmarksModel.addObserver(mBookmarkModelObserver); |
+ 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 |
@@ -129,7 +158,8 @@ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { |
mUndoController.destroy(); |
mUndoController = null; |
} |
- mEnhancedBookmarksModel.removeObserver(mBookmarkModelObserver); |
+ mEnhancedBookmarksModel.removeModelObserver(mBookmarkModelObserver); |
+ mEnhancedBookmarksModel.removeFiltersObserver(mFiltersObserver); |
mEnhancedBookmarksModel.destroy(); |
mEnhancedBookmarksModel = null; |
} |
@@ -207,20 +237,24 @@ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { |
*/ |
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 == UIState.STATE_LOADING) { |
+ } 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 != UIState.STATE_LOADING) { |
+ 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 |
@@ -250,6 +284,34 @@ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { |
PREF_LAST_USED_URL, UrlConstants.BOOKMARKS_URL); |
} |
+ private void saveListModePreference() { |
+ PreferenceManager.getDefaultSharedPreferences(mActivity).edit() |
+ .putInt(PREF_WAS_IN_LIST_MODE, mListModeEnabled ? ViewMode.LIST : ViewMode.GRID) |
+ .apply(); |
+ } |
+ |
+ private boolean getListModePreference() { |
+ int mode = PreferenceManager.getDefaultSharedPreferences(mActivity).getInt( |
+ PREF_WAS_IN_LIST_MODE, ViewMode.DEFAULT); |
+ |
+ if (mode == ViewMode.DEFAULT) mode = EnhancedBookmarksBridge.getDefaultViewMode(); |
+ |
+ return mode == ViewMode.LIST ? 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, |
+ ViewMode.DEFAULT); |
+ 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}. |
@@ -269,12 +331,12 @@ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { |
} |
if (!mStateStack.isEmpty()) { |
if (mStateStack.peek().equals(state)) return; |
- if (mStateStack.peek().mState == UIState.STATE_LOADING) { |
+ if (mStateStack.peek().mState == STATE_LOADING) { |
mStateStack.pop(); |
} |
} |
mStateStack.push(state); |
- if (state.mState != UIState.STATE_LOADING) { |
+ 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. |
@@ -292,11 +354,19 @@ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { |
@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)); |
} |
@@ -337,16 +407,30 @@ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { |
} |
@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 UIState.STATE_ALL_BOOKMARKS: |
+ case STATE_ALL_BOOKMARKS: |
observer.onAllBookmarksStateSet(); |
break; |
- case UIState.STATE_FOLDER: |
+ case STATE_FOLDER: |
observer.onFolderStateSet(mStateStack.peek().mFolder); |
break; |
- case UIState.STATE_LOADING: |
+ 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(); |
@@ -375,16 +459,42 @@ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { |
} |
@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(); |
- if (mEnhancedBookmarksModel.getBookmarkById(bookmark) != null) { |
- NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_BOOKMARK); |
- RecordHistogram.recordEnumeratedHistogram("Stars.LaunchLocation", launchLocation, |
- LaunchLocation.COUNT); |
- EnhancedBookmarkUtils.openBookmark(mActivity, |
- mEnhancedBookmarksModel.getBookmarkById(bookmark).getUrl()); |
- finishActivityOnPhone(); |
- } |
+ 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 |
@@ -412,7 +522,7 @@ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { |
@Override |
public int getCurrentState() { |
- if (mStateStack.isEmpty()) return UIState.STATE_LOADING; |
+ if (mStateStack.isEmpty()) return STATE_LOADING; |
return mStateStack.peek().mState; |
} |
@@ -420,50 +530,56 @@ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { |
* 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. |
*/ |
- static class UIState { |
- private static final int STATE_INVALID = 0; |
- static final int STATE_LOADING = 1; |
- static final int STATE_ALL_BOOKMARKS = 2; |
- static final int STATE_FOLDER = 3; |
- static final int STATE_FILTER = 4; |
- |
+ private static class UIState { |
private static final String TAG = "UIState"; |
private static final String URL_CHARSET = "UTF-8"; |
/** |
- * One of the STATE_* constants. |
+ * One of the four states: |
+ * {@link EnhancedBookmarkDelegate#STATE_ALL_BOOKMARKS}, |
+ * {@link EnhancedBookmarkDelegate#STATE_FILTER}, |
+ * {@link EnhancedBookmarkDelegate#STATE_FOLDER}, |
+ * {@link EnhancedBookmarkDelegate#STATE_LOADING}, |
*/ |
- private int mState; |
- private String mUrl; |
- private BookmarkId mFolder; |
+ int mState; |
+ String mUrl; |
+ BookmarkId mFolder; |
+ String mFilter; |
- private static UIState createLoadingState(String url) { |
+ static UIState createLoadingState(String url) { |
UIState state = new UIState(); |
state.mUrl = url; |
state.mState = STATE_LOADING; |
return state; |
} |
- private static UIState createAllBookmarksState(EnhancedBookmarksModel bookmarkModel) { |
+ static UIState createAllBookmarksState(EnhancedBookmarksModel bookmarkModel) { |
return createStateFromUrl(UrlConstants.BOOKMARKS_URL, bookmarkModel); |
} |
- private static UIState createFolderState(BookmarkId folder, |
- EnhancedBookmarksModel 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. |
*/ |
- private static UIState createStateFromUrl(String url, |
- EnhancedBookmarksModel bookmarkModel) { |
+ static UIState createStateFromUrl(String url, EnhancedBookmarksModel bookmarkModel) { |
UIState state = new UIState(); |
- state.mState = STATE_INVALID; |
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()) { |
@@ -480,26 +596,26 @@ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { |
return state; |
} |
- private UIState() { |
- } |
- |
/** |
* @return Whether this state is valid. |
*/ |
- private boolean isValid(EnhancedBookmarksModel bookmarkModel) { |
- if (mUrl == null || mState == STATE_INVALID) return false; |
- |
+ 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; |
} |
- private static String decodeSuffix(String url, String prefix) { |
+ static String decodeSuffix(String url, String prefix) { |
String suffix = url.substring(prefix.length()); |
try { |
suffix = URLDecoder.decode(suffix, URL_CHARSET); |
@@ -509,7 +625,7 @@ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { |
return suffix; |
} |
- private static String encodeUrl(String prefix, String suffix) { |
+ static String encodeUrl(String prefix, String suffix) { |
try { |
suffix = URLEncoder.encode(suffix, URL_CHARSET); |
} catch (UnsupportedEncodingException e) { |