| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.android.keyguard; |
| |
| import android.animation.Animator; |
| import android.animation.AnimatorSet; |
| import android.animation.ObjectAnimator; |
| import android.animation.PropertyValuesHolder; |
| import android.content.Context; |
| import android.util.AttributeSet; |
| import android.view.View; |
| import android.view.animation.AccelerateInterpolator; |
| import android.view.animation.DecelerateInterpolator; |
| import android.view.animation.Interpolator; |
| |
| import java.util.ArrayList; |
| |
| public class KeyguardWidgetCarousel extends KeyguardWidgetPager { |
| |
| private float mAdjacentPagesAngle; |
| private static float MAX_SCROLL_PROGRESS = 1.3f; |
| private static float CAMERA_DISTANCE = 10000; |
| protected AnimatorSet mChildrenTransformsAnimator; |
| float[] mTmpTransform = new float[3]; |
| |
| public KeyguardWidgetCarousel(Context context, AttributeSet attrs) { |
| this(context, attrs, 0); |
| } |
| |
| public KeyguardWidgetCarousel(Context context) { |
| this(context, null, 0); |
| } |
| |
| public KeyguardWidgetCarousel(Context context, AttributeSet attrs, int defStyle) { |
| super(context, attrs, defStyle); |
| mAdjacentPagesAngle = context.getResources().getInteger(R.integer.kg_carousel_angle); |
| } |
| |
| protected float getMaxScrollProgress() { |
| return MAX_SCROLL_PROGRESS; |
| } |
| |
| public float getAlphaForPage(int screenCenter, int index, boolean showSidePages) { |
| View child = getChildAt(index); |
| if (child == null) return 0f; |
| |
| boolean inVisibleRange = index >= getNextPage() - 1 && index <= getNextPage() + 1; |
| float scrollProgress = getScrollProgress(screenCenter, child, index); |
| |
| if (isOverScrollChild(index, scrollProgress)) { |
| return 1.0f; |
| } else if ((showSidePages && inVisibleRange) || index == getNextPage()) { |
| scrollProgress = getBoundedScrollProgress(screenCenter, child, index); |
| float alpha = 1.0f - 1.0f * Math.abs(scrollProgress / MAX_SCROLL_PROGRESS); |
| return alpha; |
| } else { |
| return 0f; |
| } |
| } |
| |
| public float getOutlineAlphaForPage(int screenCenter, int index, boolean showSidePages) { |
| boolean inVisibleRange = index >= getNextPage() - 1 && index <= getNextPage() + 1; |
| if (inVisibleRange) { |
| return super.getOutlineAlphaForPage(screenCenter, index, showSidePages); |
| } else { |
| return 0f; |
| } |
| } |
| |
| private void updatePageAlphaValues(int screenCenter) { |
| if (mChildrenOutlineFadeAnimation != null) { |
| mChildrenOutlineFadeAnimation.cancel(); |
| mChildrenOutlineFadeAnimation = null; |
| } |
| boolean showSidePages = mShowingInitialHints || isPageMoving(); |
| if (!isReordering(false)) { |
| for (int i = 0; i < getChildCount(); i++) { |
| KeyguardWidgetFrame child = getWidgetPageAt(i); |
| if (child != null) { |
| float outlineAlpha = getOutlineAlphaForPage(screenCenter, i, showSidePages); |
| float contentAlpha = getAlphaForPage(screenCenter, i,showSidePages); |
| child.setBackgroundAlpha(outlineAlpha); |
| child.setContentAlpha(contentAlpha); |
| } |
| } |
| } |
| } |
| |
| public void showInitialPageHints() { |
| mShowingInitialHints = true; |
| int count = getChildCount(); |
| for (int i = 0; i < count; i++) { |
| boolean inVisibleRange = i >= getNextPage() - 1 && i <= getNextPage() + 1; |
| KeyguardWidgetFrame child = getWidgetPageAt(i); |
| if (inVisibleRange) { |
| child.setBackgroundAlpha(KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER); |
| child.setContentAlpha(1f); |
| } else { |
| child.setBackgroundAlpha(0f); |
| child.setContentAlpha(0f); |
| } |
| } |
| } |
| |
| @Override |
| protected void screenScrolled(int screenCenter) { |
| mScreenCenter = screenCenter; |
| updatePageAlphaValues(screenCenter); |
| if (isReordering(false)) return; |
| for (int i = 0; i < getChildCount(); i++) { |
| KeyguardWidgetFrame v = getWidgetPageAt(i); |
| float scrollProgress = getScrollProgress(screenCenter, v, i); |
| float boundedProgress = getBoundedScrollProgress(screenCenter, v, i); |
| if (v == mDragView || v == null) continue; |
| v.setCameraDistance(CAMERA_DISTANCE); |
| |
| if (isOverScrollChild(i, scrollProgress)) { |
| v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress); |
| v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0); |
| } else { |
| int width = v.getMeasuredWidth(); |
| float pivotX = (width / 2f) + boundedProgress * (width / 2f); |
| float pivotY = v.getMeasuredHeight() / 2; |
| float rotationY = - mAdjacentPagesAngle * boundedProgress; |
| v.setPivotX(pivotX); |
| v.setPivotY(pivotY); |
| v.setRotationY(rotationY); |
| v.setOverScrollAmount(0f, false); |
| } |
| float alpha = v.getAlpha(); |
| // If the view has 0 alpha, we set it to be invisible so as to prevent |
| // it from accepting touches |
| if (alpha == 0) { |
| v.setVisibility(INVISIBLE); |
| } else if (v.getVisibility() != VISIBLE) { |
| v.setVisibility(VISIBLE); |
| } |
| } |
| } |
| |
| void animatePagesToNeutral() { |
| if (mChildrenTransformsAnimator != null) { |
| mChildrenTransformsAnimator.cancel(); |
| mChildrenTransformsAnimator = null; |
| } |
| |
| int count = getChildCount(); |
| PropertyValuesHolder alpha; |
| PropertyValuesHolder outlineAlpha; |
| PropertyValuesHolder rotationY; |
| ArrayList<Animator> anims = new ArrayList<Animator>(); |
| |
| for (int i = 0; i < count; i++) { |
| KeyguardWidgetFrame child = getWidgetPageAt(i); |
| boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1); |
| if (!inVisibleRange) { |
| child.setRotationY(0f); |
| } |
| alpha = PropertyValuesHolder.ofFloat("contentAlpha", 1.0f); |
| outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", |
| KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER); |
| rotationY = PropertyValuesHolder.ofFloat("rotationY", 0f); |
| ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha, rotationY); |
| child.setVisibility(VISIBLE); |
| if (!inVisibleRange) { |
| a.setInterpolator(mSlowFadeInterpolator); |
| } |
| anims.add(a); |
| } |
| |
| int duration = REORDERING_ZOOM_IN_OUT_DURATION; |
| mChildrenTransformsAnimator = new AnimatorSet(); |
| mChildrenTransformsAnimator.playTogether(anims); |
| |
| mChildrenTransformsAnimator.setDuration(duration); |
| mChildrenTransformsAnimator.start(); |
| } |
| |
| private void getTransformForPage(int screenCenter, int index, float[] transform) { |
| View child = getChildAt(index); |
| float boundedProgress = getBoundedScrollProgress(screenCenter, child, index); |
| float rotationY = - mAdjacentPagesAngle * boundedProgress; |
| int width = child.getMeasuredWidth(); |
| float pivotX = (width / 2f) + boundedProgress * (width / 2f); |
| float pivotY = child.getMeasuredHeight() / 2; |
| |
| transform[0] = pivotX; |
| transform[1] = pivotY; |
| transform[2] = rotationY; |
| } |
| |
| Interpolator mFastFadeInterpolator = new Interpolator() { |
| Interpolator mInternal = new DecelerateInterpolator(1.5f); |
| float mFactor = 2.5f; |
| @Override |
| public float getInterpolation(float input) { |
| return mInternal.getInterpolation(Math.min(mFactor * input, 1f)); |
| } |
| }; |
| |
| Interpolator mSlowFadeInterpolator = new Interpolator() { |
| Interpolator mInternal = new AccelerateInterpolator(1.5f); |
| float mFactor = 1.3f; |
| @Override |
| public float getInterpolation(float input) { |
| input -= (1 - 1 / mFactor); |
| input = mFactor * Math.max(input, 0f); |
| return mInternal.getInterpolation(input); |
| } |
| }; |
| |
| void animatePagesToCarousel() { |
| if (mChildrenTransformsAnimator != null) { |
| mChildrenTransformsAnimator.cancel(); |
| mChildrenTransformsAnimator = null; |
| } |
| |
| int count = getChildCount(); |
| PropertyValuesHolder alpha; |
| PropertyValuesHolder outlineAlpha; |
| PropertyValuesHolder rotationY; |
| PropertyValuesHolder pivotX; |
| PropertyValuesHolder pivotY; |
| ArrayList<Animator> anims = new ArrayList<Animator>(); |
| |
| for (int i = 0; i < count; i++) { |
| KeyguardWidgetFrame child = getWidgetPageAt(i); |
| float finalAlpha = getAlphaForPage(mScreenCenter, i, true); |
| float finalOutlineAlpha = getOutlineAlphaForPage(mScreenCenter, i, true); |
| getTransformForPage(mScreenCenter, i, mTmpTransform); |
| |
| boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1); |
| |
| ObjectAnimator a; |
| alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalAlpha); |
| outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", finalOutlineAlpha); |
| pivotX = PropertyValuesHolder.ofFloat("pivotX", mTmpTransform[0]); |
| pivotY = PropertyValuesHolder.ofFloat("pivotY", mTmpTransform[1]); |
| rotationY = PropertyValuesHolder.ofFloat("rotationY", mTmpTransform[2]); |
| |
| if (inVisibleRange) { |
| // for the central pages we animate into a rotated state |
| a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha, |
| pivotX, pivotY, rotationY); |
| } else { |
| a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha); |
| a.setInterpolator(mFastFadeInterpolator); |
| } |
| anims.add(a); |
| } |
| |
| int duration = REORDERING_ZOOM_IN_OUT_DURATION; |
| mChildrenTransformsAnimator = new AnimatorSet(); |
| mChildrenTransformsAnimator.playTogether(anims); |
| |
| mChildrenTransformsAnimator.setDuration(duration); |
| mChildrenTransformsAnimator.start(); |
| } |
| |
| protected void reorderStarting() { |
| mViewStateManager.fadeOutSecurity(REORDERING_ZOOM_IN_OUT_DURATION); |
| animatePagesToNeutral(); |
| } |
| |
| protected boolean zoomIn(final Runnable onCompleteRunnable) { |
| animatePagesToCarousel(); |
| return super.zoomIn(onCompleteRunnable); |
| } |
| |
| @Override |
| protected void onEndReordering() { |
| super.onEndReordering(); |
| mViewStateManager.fadeInSecurity(REORDERING_ZOOM_IN_OUT_DURATION); |
| } |
| } |