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

Unified Diff: chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDetailActivity.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/EnhancedBookmarkDetailActivity.java
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDetailActivity.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDetailActivity.java
new file mode 100644
index 0000000000000000000000000000000000000000..c08b30a306668d6b5556f14e124b4a73a0e8aef5
--- /dev/null
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDetailActivity.java
@@ -0,0 +1,465 @@
+// 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.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.os.Build;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.transition.Fade;
+import android.transition.Transition;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.google.android.apps.chrome.R;
+
+import org.chromium.chrome.browser.BookmarksBridge.BookmarkItem;
+import org.chromium.chrome.browser.BookmarksBridge.BookmarkModelObserver;
+import org.chromium.chrome.browser.UrlUtilities;
+import org.chromium.chrome.browser.enhanced_bookmarks.EnhancedBookmarksBridge.FiltersObserver;
+import org.chromium.chrome.browser.enhanced_bookmarks.EnhancedBookmarksBridge.SalientImageCallback;
+import org.chromium.chrome.browser.enhanced_bookmarks.EnhancedBookmarksModel;
+import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarkDetailScrollView.OnScrollListener;
+import org.chromium.chrome.browser.widget.FadingShadow;
+import org.chromium.chrome.browser.widget.FadingShadowView;
+import org.chromium.chrome.browser.widget.FlowLayout;
+import org.chromium.components.bookmarks.BookmarkId;
+import org.chromium.components.bookmarks.BookmarkType;
+import org.chromium.ui.base.DeviceFormFactor;
+
+/**
+ * Dialog to show details of the selected bookmark. It has two modes: read-only mode and editing
+ * mode. Clicking on a textview will make the dialog animate to editing mode. On a handset this
+ * dialog will be full-screen; on tablet it will be a fixed-size dialog popping up in the middle of
+ * the screen.
+ */
+public class EnhancedBookmarkDetailActivity extends EnhancedBookmarkActivityBase implements
+ View.OnClickListener, OnScrollListener, FiltersObserver {
+ public static final String INTENT_BOOKMARK_ID = "EnhancedBookmarkDetailActivity.BookmarkId";
+ private static final int ANIMATION_DURATION_MS = 300;
+
+ private EnhancedBookmarksModel mEnhancedBookmarksModel;
+ private BookmarkId mBookmarkId;
+
+ private EnhancedBookmarkDetailScrollView mScrollView;
+ private LinearLayout mContentLayout;
+ private ImageView mImageView;
+ private EditText mTitleEditText;
+ private EditText mUrlEditText;
+ private View mFolderBox;
+ private TextView mFolderTextView;
+ private TextView mAutoFoldersLabel;
+ private FlowLayout mAutoFoldersFlowLayout;
+ private EditText mDescriptionEditText;
+ private View mMaskView;
+ private RelativeLayout mActionBarLayout;
+ private ImageButton mCloseButton;
+ private ImageButton mDeleteButton;
+ private ImageButton mSaveButton;
+ private FadingShadowView mImageShadowMask;
+ private FadingShadowView mShadow;
+ private View mBottomSpacer;
+ private EditText[] mEditTexts;
+
+ private Animator mCurrentAnimator;
+ private int mDominantColor;
+ private boolean mIsEditingMode;
+
+ private BookmarkModelObserver mBookmarkModelObserver = new BookmarkModelObserver() {
+ @Override
+ public void bookmarkNodeRemoved(BookmarkItem parent, int oldIndex, BookmarkItem node,
+ boolean isDoingExtensiveChanges) {
+ if (mBookmarkId.equals(node.getId())) {
+ dismiss();
+ }
+ }
+
+ @Override
+ public void bookmarkNodeMoved(BookmarkItem oldParent, int oldIndex, BookmarkItem newParent,
+ int newIndex) {
+ BookmarkId movedBookmark = mEnhancedBookmarksModel.getChildAt(newParent.getId(),
+ newIndex);
+ if (movedBookmark.equals(mBookmarkId)) {
+ setParentFolderName(newParent.getId());
+ }
+ }
+
+ @Override
+ public void bookmarkNodeChanged(BookmarkItem node) {
+ if (mBookmarkId.equals(node.getId())) updateViews(node);
+ }
+
+ @Override
+ public void bookmarkModelChanged() {
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ EnhancedBookmarkUtils.setTaskDescriptionInDocumentMode(this,
+ getString(R.string.accessibility_enhanced_bookmark_detail_view));
+ mEnhancedBookmarksModel = new EnhancedBookmarksModel();
+ mBookmarkId = BookmarkId.getBookmarkIdFromString(
+ getIntent().getStringExtra(INTENT_BOOKMARK_ID));
+ mEnhancedBookmarksModel.addModelObserver(mBookmarkModelObserver);
+ mEnhancedBookmarksModel.addFiltersObserver(this);
+ setContentView(R.layout.eb_detail);
+ mScrollView = (EnhancedBookmarkDetailScrollView) findViewById(
+ R.id.eb_detail_scroll_view);
+ mContentLayout = (LinearLayout) findViewById(R.id.eb_detail_content);
+ mImageView = (ImageView) findViewById(R.id.eb_detail_image_view);
+ mTitleEditText = (EditText) findViewById(R.id.eb_detail_title);
+ mUrlEditText = (EditText) findViewById(R.id.eb_detail_url);
+ mFolderBox = findViewById(R.id.eb_detail_folder_box);
+ mFolderTextView = (TextView) findViewById(R.id.eb_detail_folder_textview);
+ mAutoFoldersLabel = (TextView) findViewById(R.id.eb_detail_auto_folder_label);
+ mAutoFoldersFlowLayout = (FlowLayout) findViewById(R.id.eb_detail_flow_layout);
+ mDescriptionEditText = (EditText) findViewById(R.id.eb_detail_description);
+ mMaskView = findViewById(R.id.eb_detail_image_mask);
+ mActionBarLayout = (RelativeLayout) findViewById(R.id.eb_detail_action_bar);
+ mSaveButton = (ImageButton) findViewById(R.id.eb_detail_actionbar_save_button);
+ mDeleteButton = (ImageButton) findViewById(R.id.eb_detail_actionbar_delete_button);
+ mCloseButton = (ImageButton) findViewById(R.id.eb_detail_actionbar_close_button);
+ mImageShadowMask = (FadingShadowView) findViewById(R.id.eb_detail_top_shadow);
+ mShadow = (FadingShadowView) findViewById(R.id.eb_detail_shadow);
+ mBottomSpacer = mScrollView.findViewById(R.id.bottom_spacer);
+ mEditTexts = new EditText[]{mTitleEditText, mUrlEditText, mDescriptionEditText};
+
+ // Listen to click event of EditTexts while setting them not focusable in order to
+ // postpone showing soft keyboard until animations are finished.
+ for (EditText editText : mEditTexts) editText.setOnClickListener(this);
+ clearErrorWhenNonEmpty(mEditTexts);
+ int shadowColor = getResources().getColor(
+ R.color.enhanced_bookmark_detail_dialog_shadow_color);
+ mShadow.init(shadowColor, FadingShadow.POSITION_TOP);
+ mImageShadowMask.init(shadowColor, FadingShadow.POSITION_TOP);
+ mImageShadowMask.setStrength(1.0f);
+
+ mSaveButton.setOnClickListener(this);
+ mDeleteButton.setOnClickListener(this);
+ mCloseButton.setOnClickListener(this);
+ mFolderBox.setOnClickListener(this);
+
+ mScrollView.setOnScrollListener(this);
+
+ updateViews();
+ updateAutoFolders();
+ setUpSharedElementAnimation();
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private void setUpSharedElementAnimation() {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return;
+ Transition t = new Fade();
+ // Exlude status bar and navigation bar, to work around an Android bug that white background
+ // activity will cause these two bars blink/flash during content transition.
+ t.excludeTarget(android.R.id.statusBarBackground, true);
+ t.excludeTarget(android.R.id.navigationBarBackground, true);
+ getWindow().setEnterTransition(t);
+ getWindow().setExitTransition(t);
+ }
+
+ /**
+ * Custom {@link android.app.Activity#finish()} that checks device version. If in Lollipop or
+ * future releases, it enables finish with backward shared element animation.
+ */
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private void dismiss() {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) finish();
+ else finishAfterTransition();
+ }
+
+ @Override
+ public void onBackPressed() {
+ onClick(mCloseButton);
+ }
+
+ private void updateViews() {
+ BookmarkItem bookmarkItem = mEnhancedBookmarksModel.getBookmarkById(mBookmarkId);
+ updateViews(bookmarkItem);
+ }
+
+ /**
+ * Updates each EditText to display the data in bookmarkItem. This function will be called every
+ * time user cancels editing.
+ */
+ private void updateViews(BookmarkItem bookmarkItem) {
+ mTitleEditText.setText(bookmarkItem.getTitle());
+ mUrlEditText.setText(bookmarkItem.getUrl());
+ setParentFolderName(bookmarkItem.getParentId());
+
+ if (bookmarkItem.getId().getType() == BookmarkType.PARTNER) {
+ mUrlEditText.setEnabled(false);
+ mDescriptionEditText.setVisibility(View.GONE);
+ } else {
+ mUrlEditText.setEnabled(true);
+ mDescriptionEditText.setText(
+ mEnhancedBookmarksModel.getBookmarkDescription(mBookmarkId));
+ mDescriptionEditText.setVisibility(View.VISIBLE);
+ }
+
+ mDominantColor = EnhancedBookmarkUtils.generateBackgroundColor(bookmarkItem);
+ mImageView.setBackgroundColor(mDominantColor);
+ mMaskView.setBackgroundColor(mDominantColor);
+ mEnhancedBookmarksModel.salientImageForUrl(bookmarkItem.getUrl(),
+ new SalientImageCallback() {
+ @Override
+ public void onSalientImageReady(Bitmap bitmap, String imageUrl) {
+ if (bitmap == null) return;
+ mImageView.setImageBitmap(bitmap);
+ mDominantColor = EnhancedBookmarkUtils.getDominantColorForBitmap(bitmap);
+ mImageView.setBackgroundColor(mDominantColor);
+ mMaskView.setBackgroundColor(mDominantColor);
+ }
+ });
+ mMaskView.setAlpha(0.0f);
+ }
+
+ private void updateAutoFolders() {
+ mAutoFoldersFlowLayout.removeAllViews();
+ String[] filters = mEnhancedBookmarksModel.getFiltersForBookmark(mBookmarkId);
+ for (String filter : filters) {
+ Button autoFolder = new AutoFolderButton(this);
+ autoFolder.setText(filter);
+ mAutoFoldersFlowLayout.addView(autoFolder);
+ }
+ if (mAutoFoldersFlowLayout.getChildCount() > 0) {
+ mAutoFoldersLabel.setVisibility(View.VISIBLE);
+ mAutoFoldersFlowLayout.setVisibility(View.VISIBLE);
+ } else {
+ mAutoFoldersLabel.setVisibility(View.GONE);
+ mAutoFoldersFlowLayout.setVisibility(View.GONE);
+ }
+ }
+
+ private void setParentFolderName(BookmarkId parentId) {
+ mFolderTextView.setText(mEnhancedBookmarksModel.getBookmarkTitle(parentId));
+ mFolderTextView.setEnabled(parentId.getType() != BookmarkType.PARTNER);
+ }
+
+ @Override
+ public void onClick(View v) {
+ // During animation, do not respond to any clicking events.
+ if (mCurrentAnimator != null) return;
+ if (v == mCloseButton) {
+ if (mIsEditingMode) leaveEditingMode(false);
+ else dismiss();
+ } else if (v == mSaveButton) {
+ if (mIsEditingMode) leaveEditingMode(true);
+ else dismiss();
+ } else if (v instanceof EditText) {
+ if (!mIsEditingMode) enterEditingMode((EditText) v);
+ } else if (v == mFolderBox) {
+ EnhancedBookmarkFolderSelectActivity.startFolderSelectActivity(this, mBookmarkId);
+ } else if (v == mDeleteButton) {
+ mEnhancedBookmarksModel.deleteBookmarks(mBookmarkId);
+ dismiss();
+ }
+ }
+
+ /**
+ * Entering editing mode will trigger scrolling-up animation, as an effort to smoothly place the
+ * focused EditText to be the best editable position to user. After animating, corresponding
+ * EditText will be given a simulated touch event that shows up soft keyboard and allow user to
+ * edit.
+ * <p>
+ * To ensure the view can always be scrolled up to enter editing mode, before animation: 1). If
+ * content is shorter than screen height, then we fill the content view by emptyAreaHeight so as
+ * to align the content and scroll view. 2). Calculate the scrolling amount. 3). If the
+ * scrolling amount is larger than the current maximum scrollable amount, increase height of
+ * mBottomSpacer to make the content long enough. 4).trigger scroll-up animation.
+ */
+ private void enterEditingMode(final EditText editText) {
+ if (mIsEditingMode) return;
+ mIsEditingMode = true;
+
+ if (DeviceFormFactor.isTablet(this)) {
+ // On tablet this the size of the dialog is controlled by framework. To avoid any
+ // jumpy behavior, we skip the crazy scrolling effect below.
+ animateScrolling(mScrollView.getScrollY(), editText);
+ } else {
+ int scrollAmount = mScrollView.getHeightCompensation() + editText.getTop()
+ - mTitleEditText.getTop();
+
+ // If there is not enough space to scroll, create padding at bottom.
+ if (scrollAmount > mScrollView.getMaximumScrollY()) {
+ // First try to align content view and scroll view.
+ int emptyAreaHeight = mScrollView.getHeight() - mContentLayout.getHeight();
+ if (emptyAreaHeight < 0) emptyAreaHeight = 0;
+ // Then increase height of bottom spacer to create margin for scroll.
+ setViewHeight(mBottomSpacer,
+ scrollAmount - mScrollView.getMaximumScrollY() + emptyAreaHeight);
+ }
+
+ animateScrolling(scrollAmount, editText);
+ }
+ }
+
+ private void animateScrolling(int scrollAmount, final EditText editText) {
+ ObjectAnimator animator = ObjectAnimator.ofInt(mScrollView, "scrollY", scrollAmount);
+ animator.setDuration(scrollAmount == mScrollView.getScrollY() ? 0 : ANIMATION_DURATION_MS);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ for (EditText text : mEditTexts) text.setFocusableInTouchMode(true);
+ editText.requestFocus();
+ InputMethodManager imm = (InputMethodManager) getSystemService(
+ Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(editText, 0);
+ mCurrentAnimator = null;
+ }
+ });
+ mCurrentAnimator = animator;
+ animator.start();
+ }
+
+ /**
+ * Leaves editing mode and finishes the activity. If shouldSave is set false, all changes will
+ * be reverted.
+ */
+ private void leaveEditingMode(boolean shouldSave) {
+ assert mIsEditingMode;
+
+ String newTitle = mTitleEditText.getText().toString().trim();
+ String newUrl = mUrlEditText.getText().toString().trim();
+ if (shouldSave) {
+ boolean urlOrTitleInvalid = false;
+ // Fix user input urls, if necessary.
+ newUrl = UrlUtilities.fixupUrl(newUrl);
+ if (newUrl == null) newUrl = "";
+ mUrlEditText.setText(newUrl);
+ if (newUrl.isEmpty()) {
+ mUrlEditText.setError(getString(R.string.bookmark_missing_url));
+ urlOrTitleInvalid = true;
+ }
+ if (newTitle.isEmpty()) {
+ mTitleEditText.setError(getString(R.string.bookmark_missing_title));
+ urlOrTitleInvalid = true;
+ }
+ if (urlOrTitleInvalid) return;
+ }
+
+ mIsEditingMode = false;
+
+ if (shouldSave) {
+ BookmarkItem bookmarkItem = mEnhancedBookmarksModel.getBookmarkById(mBookmarkId);
+ String newDescription = mDescriptionEditText.getText().toString().trim();
+ if (!bookmarkItem.getTitle().equals(newTitle)) {
+ mEnhancedBookmarksModel.setBookmarkTitle(mBookmarkId, newTitle);
+ }
+ if (!bookmarkItem.getUrl().equals(newUrl)
+ && bookmarkItem.getId().getType() != BookmarkType.PARTNER) {
+ mEnhancedBookmarksModel.setBookmarkUrl(mBookmarkId, newUrl);
+ }
+ if (bookmarkItem.getId().getType() != BookmarkType.PARTNER) {
+ mEnhancedBookmarksModel.setBookmarkDescription(mBookmarkId, newDescription);
+ }
+ } else {
+ // If user discards change, restore textviews to original values.
+ updateViews();
+ }
+
+ mContentLayout.requestFocus();
+ InputMethodManager imm = (InputMethodManager) getSystemService(
+ Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(mTitleEditText.getWindowToken(), 0);
+ // Cancel error state of message
+ mUrlEditText.setError(null);
+ mTitleEditText.setError(null);
+ // Reset all EditTexts to be not focosable to postpone showing keyboard
+ for (EditText editText : mEditTexts) editText.setFocusable(false);
+ mCurrentAnimator = null;
+ if (mBottomSpacer.getHeight() != 0) setViewHeight(mBottomSpacer, 0);
+ dismiss();
+ }
+
+ @Override
+ public void onScrollChanged(int y, int oldY) {
+ int offset = mScrollView.getHeightCompensation();
+ if (y < offset) {
+ mMaskView.setAlpha(y / (float) offset);
+ mActionBarLayout.setBackgroundResource(0);
+ mShadow.setStrength(0.0f);
+ } else {
+ mMaskView.setAlpha(1.0f);
+ mActionBarLayout.setBackgroundColor(mDominantColor);
+ mShadow.setStrength(1.0f);
+ }
+
+ }
+
+ /**
+ * Adds a listener to EditTexts that clears the TextView's error once the user types something.
+ */
+ private void clearErrorWhenNonEmpty(TextView... textViews) {
+ for (final TextView textView : textViews) {
+ textView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (s.length() != 0 && textView.getError() != null) textView.setError(null);
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ mEnhancedBookmarksModel.removeModelObserver(mBookmarkModelObserver);
+ mEnhancedBookmarksModel.destroy();
+ mEnhancedBookmarksModel = null;
+ super.onDestroy();
+ }
+
+ @Override
+ public void onFiltersChanged() {
+ updateAutoFolders();
+ }
+
+ private static void setViewHeight(View view, int height) {
+ ViewGroup.LayoutParams lp = view.getLayoutParams();
+ lp.height = height;
+ view.setLayoutParams(lp);
+ }
+
+ /**
+ * Rounded button for auto folders in bookmark detail page.
+ */
+ private static class AutoFolderButton extends Button {
+
+ private static final int TEXT_SIZE_SP = 14;
+
+ public AutoFolderButton(Context context) {
+ super(context);
+ setTextSize(TEXT_SIZE_SP);
+ // Force auto folder buttons smaller than android default size.
+ setMinHeight(0);
+ setMinimumHeight(0);
+ setMinWidth(0);
+ setMinimumWidth(0);
+ setBackgroundResource(R.drawable.btn_enhanced_bookmark_auto_folder);
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698