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

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/firstrun/ImageCarousel.java

Issue 1840513002: Redesign sign in and sign in confirmation screens for Narnia 2.0 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address comments Created 4 years, 8 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/src/org/chromium/chrome/browser/firstrun/ImageCarousel.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ImageCarousel.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ImageCarousel.java
deleted file mode 100644
index c4d17b2562ffcf2f45a9671383b60c7334c0ceba..0000000000000000000000000000000000000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ImageCarousel.java
+++ /dev/null
@@ -1,437 +0,0 @@
-// 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.firstrun;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.util.AttributeSet;
-import android.util.Property;
-import android.view.GestureDetector;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.animation.DecelerateInterpolator;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import org.chromium.chrome.R;
-
-import java.util.Arrays;
-
-/**
- * Account chooser that displays profile images in a carousel and allows users to rotate it to
- * select an account.
- *
- * Internally it is implemented using four ImageViews that get translated along the X axis based
- * on the current carousel position.
- *
- * |'''''| |'''''| |'''''| |'''''| |'''''|
- * |'''| |'''| |'''| |'''| |'''| |'''| |'''| |'''| |'''| |'''|
- * |IM3| IM0 |IM1| -> |IM0| IM1 |IM2| -> |IM1| IM2 |IM3| -> |IM2| IM3 |IM0| -> |IM3| IM0 |IM1|
- * |,,,| |,,,| |,,,| |,,,| |,,,| |,,,| |,,,| |,,,| |,,,| |,,,|
- * |,,,,,| |,,,,,| |,,,,,| |,,,,,| |,,,,,|
- *
- * mPosition=0 mPosition=1 mPosition=2 mPosition=3 mPosition=4
- *
- * IM0 is mViews[0]
- * IM1 is mViews[1]
- * IM2 is mViews[2]
- * IM3 is mViews[3]
- *
- * Each ImageView is displaying a profile image if there is one, however it is not necessarily true
- * that IM0 is showing mImages[0] and IM1 is showing mImages[1], and so on. This changes when there
- * are more than 4 accounts and ImageViews get reused for new accounts.
- */
-public class ImageCarousel extends FrameLayout implements GestureDetector.OnGestureListener {
-
- /**
- * Constant used together image width to calculate how far should should each image move in
- * x axis. This value was tweaked until images did not overlap with each other when scrolling.
- */
- private static final float TRANSLATION_FACTOR = 0.64f;
-
- /**
- * Constant used together with carousel width to calculate how should fling velocity in x axis
- * be scaled when changing ImageCarousel position. It was tweaked for flings to look natural.
- */
- private static final float FLING_FACTOR = 20f * 0.92f / 2f;
-
- /**
- * Constant used together with carousel width to calculate how should scroll distance in x axis
- * be scaled when changing ImageCarousel position. It was tweaked for image to follow user's
- * finger when scrolling.
- */
- private static final float SCROLL_FACTOR = 0.92f / 2f;
-
- /**
- * Listener to ImageCarousel center position changes.
- */
- public interface ImageCarouselPositionChangeListener {
- /**
- * @param position The new center position of the ImageCarousel. It is a number in
- * range [0, mImages.length).
- */
- void onPositionChanged(int position);
- }
-
- private static final int SCROLL_ANIMATION_DURATION_MS = 200;
- private static final int ACCOUNT_SIGNED_IN_ANIMATION_DURATION_MS = 200;
-
- private static final float MINIMUM_POSITION_TWO_IMAGES = -0.1f;
- private static final float MAXIMUM_POSITION_TWO_IMAGES = 1.1f;
-
- /**
- * Number of ImageViews used in ImageCarousel.
- */
- private static final int VIEW_COUNT = 4;
-
- private static final int[] ORDER_OFFSETS = {2, 1, 3, 0};
-
- private static final int[] POSITION_OFFSETS = {0, -1, 2, 1};
-
- private static final int[] BITMAP_OFFSETS = {2, 1, -1, 0};
-
- /**
- * Property used to animate scrolling of the ImageCarousel.
- */
- private static final Property<ImageCarousel, Float> POSITION_PROPERTY =
- new Property<ImageCarousel, Float>(Float.class, "") {
- @Override
- public Float get(ImageCarousel object) {
- return object.mPosition;
- }
-
- @Override
- public void set(ImageCarousel object, Float value) {
- object.setPosition(value);
- }
- };
-
- /**
- * Property used to animate the alpha value of the images that are currently on the left and
- * the right of the center image.
- */
- private static final Property<ImageCarousel, Float> BACKGROUND_IMAGE_ALPHA =
- new Property<ImageCarousel, Float>(Float.class, "") {
- @Override
- public Float get(ImageCarousel object) {
- return object.mViews[object.getChildDrawingOrder(VIEW_COUNT, 1)].getAlpha();
- }
-
- @Override
- public void set(ImageCarousel object, Float value) {
- object.mViews[object.getChildDrawingOrder(VIEW_COUNT, 1)].setAlpha(value);
- object.mViews[object.getChildDrawingOrder(VIEW_COUNT, 2)].setAlpha(value);
- }
- };
-
- /**
- * Gesture detector used to capture scrolls, flings and taps on the image carousel.
- */
- private GestureDetector mGestureDetector;
-
- /**
- * Array that holds four ImageViews that are used to display images in the carousel.
- */
- private ImageView[] mViews = new ImageView[VIEW_COUNT];
-
- /**
- * Images that shown in the image carousel.
- */
- private Bitmap[] mImages;
-
- private Animator mScrollAnimator;
- private Animator mFadeInOutAnimator;
-
- private float mPosition = 0f;
-
- private ImageCarouselPositionChangeListener mListener;
- private ImageView mCheckmark;
- private int mLastPosition = 0;
- private boolean mNeedsPositionUpdates = true;
-
- private int mCarouselWidth;
- private int mImageWidth;
- private float mScrollScalingFactor;
- private float mFlingScalingFactor;
- private float mTranslationFactor;
-
- private boolean mScrollingDisabled;
- private boolean mAccountSelected;
-
- public ImageCarousel(Context context, AttributeSet attrs) {
- super(context, attrs);
- mGestureDetector = new GestureDetector(getContext(), this);
- }
-
- /**
- * Scrolls ImageCarousel to the closest whole position for the desired position.
- * @param position Desired ImageCarousel position.
- * @param decelerate Whether animation should be decelerating.
- * @param needsPositionUpdates Whether this scroll should trigger position update calls to
- * mListener.
- */
- public void scrollTo(float position, boolean decelerate, boolean needsPositionUpdates) {
- mNeedsPositionUpdates = needsPositionUpdates;
- if (mScrollAnimator != null) mScrollAnimator.cancel();
-
- position = Math.round(position);
- if (mImages != null && mImages.length == 2) {
- if (position < 0) position = 0;
- if (position > 1) position = 1;
- }
- mScrollAnimator = ObjectAnimator.ofFloat(this, POSITION_PROPERTY, mPosition, position);
- mScrollAnimator.setDuration(SCROLL_ANIMATION_DURATION_MS);
- if (decelerate) mScrollAnimator.setInterpolator(new DecelerateInterpolator());
- mScrollAnimator.start();
- }
-
- /**
- * @param listener Listener that should be notified on ImageCarousel center position changes.
- */
- public void setListener(ImageCarouselPositionChangeListener listener) {
- mListener = listener;
- }
-
- /**
- * @param images Images that should be displayed in the ImageCarousel.
- */
- public void setImages(Bitmap[] images) {
- switch (images.length) {
- case 0:
- mImages = null;
- mScrollingDisabled = true;
- break;
- case 1:
- mScrollingDisabled = true;
- mImages = Arrays.copyOf(images, images.length);
- break;
- default:
- // Enable scrolling only if no account has already been selected.
- mScrollingDisabled = mAccountSelected;
- mImages = Arrays.copyOf(images, images.length);
- break;
- }
-
- updateImageViews();
- }
-
- /**
- * Sets whether the ImageCarousel is in signed in mode. This mode disables scrolling, animates
- * away the background images, and displays a checkmark next to the chosen account image.
- * @param isSignedIn Whether the ImageCarousel should in signed in mode or not.
- */
- public void setSignedInMode(boolean isSignedIn) {
- if (isSignedIn == mAccountSelected) return;
-
- mScrollingDisabled = isSignedIn;
- mAccountSelected = isSignedIn;
- setPosition(getCenterPosition());
-
- if (mCheckmark == null) {
- mCheckmark = new ImageView(getContext());
- mCheckmark.setImageResource(R.drawable.verify_checkmark);
- setLayoutParamsForCheckmark(mCheckmark);
- addView(mCheckmark);
- }
-
- if (mFadeInOutAnimator != null) mFadeInOutAnimator.cancel();
- AnimatorSet animatorSet = new AnimatorSet();
- if (isSignedIn) {
- animatorSet.playTogether(ObjectAnimator.ofFloat(this, BACKGROUND_IMAGE_ALPHA, 0),
- ObjectAnimator.ofFloat(mCheckmark, View.ALPHA, 0.0f, 1.0f));
- } else {
- animatorSet.playTogether(ObjectAnimator.ofFloat(this, BACKGROUND_IMAGE_ALPHA, 1),
- ObjectAnimator.ofFloat(mCheckmark, View.ALPHA, 1.0f, 0.0f));
- }
- mFadeInOutAnimator = animatorSet;
- mFadeInOutAnimator.setDuration(ACCOUNT_SIGNED_IN_ANIMATION_DURATION_MS);
- mFadeInOutAnimator.start();
- }
-
- @Override
- public void onFinishInflate() {
- super.onFinishInflate();
-
- mImageWidth = getResources().getDimensionPixelSize(R.dimen.fre_image_height);
- for (int i = 0; i < VIEW_COUNT; ++i) {
- ImageView view = new ImageView(getContext());
- FrameLayout.LayoutParams params =
- new FrameLayout.LayoutParams(mImageWidth, mImageWidth);
- params.gravity = Gravity.CENTER;
- view.setLayoutParams(params);
- mViews[i] = view;
- addView(view);
- }
-
- mCarouselWidth = getResources().getDimensionPixelSize(R.dimen.signin_image_carousel_width);
- mScrollScalingFactor = SCROLL_FACTOR * mCarouselWidth;
- mFlingScalingFactor = FLING_FACTOR * mCarouselWidth;
- mTranslationFactor = TRANSLATION_FACTOR * mImageWidth;
-
- setChildrenDrawingOrderEnabled(true);
- setPosition(0f);
- }
-
- /**
- * @return The index of the view that should be drawn on the given iteration.
- */
- @Override
- protected int getChildDrawingOrder(int childCount, int iteration) {
- // Draw the views that are not our 4 ImagesViews in their normal order.
- if (iteration >= VIEW_COUNT) return iteration;
-
- // Draw image views in the correct z order based on the current position.
- return (Math.round(mPosition) + ORDER_OFFSETS[iteration]) % VIEW_COUNT;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (mScrollingDisabled) return false;
- if (mGestureDetector.onTouchEvent(event)) return true;
-
- if (event.getAction() == MotionEvent.ACTION_UP
- || event.getAction() == MotionEvent.ACTION_CANCEL) {
- scrollTo(mPosition, false, true);
- }
-
- return false;
- }
-
- // Implementation of GestureDetector.OnGestureListener
-
- @Override
- public boolean onDown(MotionEvent motionEvent) {
- return true;
- }
-
- @Override
- public void onShowPress(MotionEvent motionEvent) {}
-
- @Override
- public boolean onSingleTapUp(MotionEvent motionEvent) {
- mNeedsPositionUpdates = true;
- if (motionEvent.getX() < (mCarouselWidth - mImageWidth) / 2f) {
- scrollTo(mPosition - 1, false, true);
- return true;
- } else if (motionEvent.getX() > (mCarouselWidth + mImageWidth) / 2f) {
- scrollTo(mPosition + 1, false, true);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- // Once the user has started scrolling, prevent the parent view from handling touch events.
- // This allows the ImageCarousel to be behave reasonably when nested inside a ScrollView.
- getParent().requestDisallowInterceptTouchEvent(true);
-
- mNeedsPositionUpdates = true;
- setPosition(mPosition + distanceX / mScrollScalingFactor);
- return true;
- }
-
- @Override
- public void onLongPress(MotionEvent motionEvent) {}
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- mNeedsPositionUpdates = true;
- scrollTo(mPosition - velocityX / mFlingScalingFactor, true, true);
- return true;
- }
-
- // Internal methods
-
- /**
- * Updates the position, scale, alpha and image shown for all four ImageViews used by
- * the ImageCarousel.
- */
- private void updateImageViews() {
- if (mImages == null) return;
-
- for (int i = 0; i < VIEW_COUNT; i++) {
- if (mAccountSelected && i != getCenterPosition()) continue;
-
- ImageView image = mViews[i];
-
- updateBitmap(i);
-
- final float position = mPosition + POSITION_OFFSETS[i];
-
- // X translation is a sin function with a period of 4 and with range
- // [-mTranslationFactor, mTranslationFactor]
- image.setTranslationX(
- -mTranslationFactor * ((float) Math.sin(position * Math.PI / 2f)));
-
- // scale is a cos function with a period of 4 and range [1/3, 1]
- // scale is 1 when the image is in the front and 1/3 when the image is behind other
- // images.
- final float scale = (float) Math.cos(position * Math.PI / 2f) / 3f + 2f / 3f;
- image.setScaleY(scale);
- image.setScaleX(scale);
-
- // alpha is a cos^2 function with a period of 2 and range [0, 1]
- // alpha is 1 when the image is in the center in the front and 0 when it is in the back.
- final float alpha = (float) Math.pow(Math.cos(position * Math.PI / 4f), 2);
- image.setAlpha(alpha);
- }
- }
-
- private void updateBitmap(int i) {
- int drawingOrder = getChildDrawingOrder(VIEW_COUNT, i);
- // Only draw one top bitmap for one image case.
- if (mImages.length == 1 && drawingOrder > 0) return;
- // Only draw two top bitmaps for two images case.
- if (mImages.length == 2 && drawingOrder > 1) return;
- ImageView image = mViews[drawingOrder];
- image.setImageBitmap(mImages[
- (mImages.length + Math.round(mPosition) + BITMAP_OFFSETS[i]) % mImages.length]);
- }
-
- private void setPosition(float position) {
- if (mImages != null) {
- if (mImages.length == 2) {
- position = Math.max(MINIMUM_POSITION_TWO_IMAGES, position);
- position = Math.min(MAXIMUM_POSITION_TWO_IMAGES, position);
- mPosition = position;
- } else {
- mPosition = ((position % mImages.length) + mImages.length) % mImages.length;
- }
- }
-
- int adjustedPosition = getCenterPosition();
- if (adjustedPosition != mLastPosition) {
- mLastPosition = adjustedPosition;
- if (mListener != null && mNeedsPositionUpdates) {
- mListener.onPositionChanged(adjustedPosition);
- }
- }
-
- // Need to call invalidate() for getChildDrawingOrder() to be called since the image
- // order has changed.
- updateImageViews();
- invalidate();
- }
-
- private int getCenterPosition() {
- if (mImages == null) return 0;
- return Math.round(mPosition) % mImages.length;
- }
-
- private void setLayoutParamsForCheckmark(View view) {
- int size = getResources().getDimensionPixelSize(R.dimen.signin_checkmark_size);
- FrameLayout.LayoutParams params =
- new FrameLayout.LayoutParams(size, size);
- params.gravity = Gravity.CENTER;
- view.setLayoutParams(params);
- view.setTranslationX((mImageWidth - size) / 2f);
- view.setTranslationY((mImageWidth - size) / 2f);
- }
-}

Powered by Google App Engine
This is Rietveld 408576698