Home | History | Annotate | Download | only in keyguard
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.keyguard;
     17 
     18 import android.animation.Animator;
     19 import android.animation.AnimatorSet;
     20 import android.animation.ObjectAnimator;
     21 import android.animation.PropertyValuesHolder;
     22 import android.content.Context;
     23 import android.util.AttributeSet;
     24 import android.view.View;
     25 import android.view.animation.AccelerateInterpolator;
     26 import android.view.animation.DecelerateInterpolator;
     27 import android.view.animation.Interpolator;
     28 
     29 import java.util.ArrayList;
     30 
     31 public class KeyguardWidgetCarousel extends KeyguardWidgetPager {
     32 
     33     private float mAdjacentPagesAngle;
     34     private static float MAX_SCROLL_PROGRESS = 1.3f;
     35     private static float CAMERA_DISTANCE = 10000;
     36     protected AnimatorSet mChildrenTransformsAnimator;
     37     float[] mTmpTransform = new float[3];
     38 
     39     public KeyguardWidgetCarousel(Context context, AttributeSet attrs) {
     40         this(context, attrs, 0);
     41     }
     42 
     43     public KeyguardWidgetCarousel(Context context) {
     44         this(context, null, 0);
     45     }
     46 
     47     public KeyguardWidgetCarousel(Context context, AttributeSet attrs, int defStyle) {
     48         super(context, attrs, defStyle);
     49         mAdjacentPagesAngle = context.getResources().getInteger(R.integer.kg_carousel_angle);
     50     }
     51 
     52     protected float getMaxScrollProgress() {
     53         return MAX_SCROLL_PROGRESS;
     54     }
     55 
     56     public float getAlphaForPage(int screenCenter, int index, boolean showSidePages) {
     57         View child = getChildAt(index);
     58         if (child == null) return 0f;
     59 
     60         boolean inVisibleRange = index >= getNextPage() - 1 && index <= getNextPage() + 1;
     61         float scrollProgress = getScrollProgress(screenCenter, child, index);
     62 
     63         if (isOverScrollChild(index, scrollProgress)) {
     64             return 1.0f;
     65         } else if ((showSidePages && inVisibleRange) || index == getNextPage()) {
     66             scrollProgress = getBoundedScrollProgress(screenCenter, child, index);
     67             float alpha = 1.0f - 1.0f * Math.abs(scrollProgress / MAX_SCROLL_PROGRESS);
     68             return alpha;
     69         } else {
     70             return 0f;
     71         }
     72     }
     73 
     74     public float getOutlineAlphaForPage(int screenCenter, int index, boolean showSidePages) {
     75         boolean inVisibleRange = index >= getNextPage() - 1 && index <= getNextPage() + 1;
     76         if (inVisibleRange) {
     77             return super.getOutlineAlphaForPage(screenCenter, index, showSidePages);
     78         } else {
     79             return 0f;
     80         }
     81     }
     82 
     83     private void updatePageAlphaValues(int screenCenter) {
     84         if (mChildrenOutlineFadeAnimation != null) {
     85             mChildrenOutlineFadeAnimation.cancel();
     86             mChildrenOutlineFadeAnimation = null;
     87         }
     88         boolean showSidePages = mShowingInitialHints || isPageMoving();
     89         if (!isReordering(false)) {
     90             for (int i = 0; i < getChildCount(); i++) {
     91                 KeyguardWidgetFrame child = getWidgetPageAt(i);
     92                 if (child != null) {
     93                     float outlineAlpha = getOutlineAlphaForPage(screenCenter, i, showSidePages);
     94                     float contentAlpha = getAlphaForPage(screenCenter, i,showSidePages);
     95                     child.setBackgroundAlpha(outlineAlpha);
     96                     child.setContentAlpha(contentAlpha);
     97                 }
     98             }
     99         }
    100     }
    101 
    102     public void showInitialPageHints() {
    103         mShowingInitialHints = true;
    104         int count = getChildCount();
    105         for (int i = 0; i < count; i++) {
    106             boolean inVisibleRange = i >= getNextPage() - 1 && i <= getNextPage() + 1;
    107             KeyguardWidgetFrame child = getWidgetPageAt(i);
    108             if (inVisibleRange) {
    109                 child.setBackgroundAlpha(KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
    110                 child.setContentAlpha(1f);
    111             } else {
    112                 child.setBackgroundAlpha(0f);
    113                 child.setContentAlpha(0f);
    114             }
    115         }
    116     }
    117 
    118     @Override
    119     protected void screenScrolled(int screenCenter) {
    120         mScreenCenter = screenCenter;
    121         updatePageAlphaValues(screenCenter);
    122         if (isReordering(false)) return;
    123         for (int i = 0; i < getChildCount(); i++) {
    124             KeyguardWidgetFrame v = getWidgetPageAt(i);
    125             float scrollProgress = getScrollProgress(screenCenter, v, i);
    126             float boundedProgress = getBoundedScrollProgress(screenCenter, v, i);
    127             if (v == mDragView || v == null) continue;
    128             v.setCameraDistance(CAMERA_DISTANCE);
    129 
    130             if (isOverScrollChild(i, scrollProgress)) {
    131                 v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress);
    132                 v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0);
    133             } else {
    134                 int width = v.getMeasuredWidth();
    135                 float pivotX = (width / 2f) + boundedProgress * (width / 2f);
    136                 float pivotY = v.getMeasuredHeight() / 2;
    137                 float rotationY = - mAdjacentPagesAngle * boundedProgress;
    138                 v.setPivotX(pivotX);
    139                 v.setPivotY(pivotY);
    140                 v.setRotationY(rotationY);
    141                 v.setOverScrollAmount(0f, false);
    142             }
    143             float alpha = v.getAlpha();
    144             // If the view has 0 alpha, we set it to be invisible so as to prevent
    145             // it from accepting touches
    146             if (alpha == 0) {
    147                 v.setVisibility(INVISIBLE);
    148             } else if (v.getVisibility() != VISIBLE) {
    149                 v.setVisibility(VISIBLE);
    150             }
    151         }
    152     }
    153 
    154     void animatePagesToNeutral() {
    155         if (mChildrenTransformsAnimator != null) {
    156             mChildrenTransformsAnimator.cancel();
    157             mChildrenTransformsAnimator = null;
    158         }
    159 
    160         int count = getChildCount();
    161         PropertyValuesHolder alpha;
    162         PropertyValuesHolder outlineAlpha;
    163         PropertyValuesHolder rotationY;
    164         ArrayList<Animator> anims = new ArrayList<Animator>();
    165 
    166         for (int i = 0; i < count; i++) {
    167             KeyguardWidgetFrame child = getWidgetPageAt(i);
    168             boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1);
    169             if (!inVisibleRange) {
    170                 child.setRotationY(0f);
    171             }
    172             alpha = PropertyValuesHolder.ofFloat("contentAlpha", 1.0f);
    173             outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha",
    174                     KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
    175             rotationY = PropertyValuesHolder.ofFloat("rotationY", 0f);
    176             ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha, rotationY);
    177             child.setVisibility(VISIBLE);
    178             if (!inVisibleRange) {
    179                 a.setInterpolator(mSlowFadeInterpolator);
    180             }
    181             anims.add(a);
    182         }
    183 
    184         int duration = REORDERING_ZOOM_IN_OUT_DURATION;
    185         mChildrenTransformsAnimator = new AnimatorSet();
    186         mChildrenTransformsAnimator.playTogether(anims);
    187 
    188         mChildrenTransformsAnimator.setDuration(duration);
    189         mChildrenTransformsAnimator.start();
    190     }
    191 
    192     private void getTransformForPage(int screenCenter, int index, float[] transform) {
    193         View child = getChildAt(index);
    194         float boundedProgress = getBoundedScrollProgress(screenCenter, child, index);
    195         float rotationY = - mAdjacentPagesAngle * boundedProgress;
    196         int width = child.getMeasuredWidth();
    197         float pivotX = (width / 2f) + boundedProgress * (width / 2f);
    198         float pivotY = child.getMeasuredHeight() / 2;
    199 
    200         transform[0] = pivotX;
    201         transform[1] = pivotY;
    202         transform[2] = rotationY;
    203     }
    204 
    205     Interpolator mFastFadeInterpolator = new Interpolator() {
    206         Interpolator mInternal = new DecelerateInterpolator(1.5f);
    207         float mFactor = 2.5f;
    208         @Override
    209         public float getInterpolation(float input) {
    210             return mInternal.getInterpolation(Math.min(mFactor * input, 1f));
    211         }
    212     };
    213 
    214     Interpolator mSlowFadeInterpolator = new Interpolator() {
    215         Interpolator mInternal = new AccelerateInterpolator(1.5f);
    216         float mFactor = 1.3f;
    217         @Override
    218         public float getInterpolation(float input) {
    219             input -= (1 - 1 / mFactor);
    220             input = mFactor * Math.max(input, 0f);
    221             return mInternal.getInterpolation(input);
    222         }
    223     };
    224 
    225     void animatePagesToCarousel() {
    226         if (mChildrenTransformsAnimator != null) {
    227             mChildrenTransformsAnimator.cancel();
    228             mChildrenTransformsAnimator = null;
    229         }
    230 
    231         int count = getChildCount();
    232         PropertyValuesHolder alpha;
    233         PropertyValuesHolder outlineAlpha;
    234         PropertyValuesHolder rotationY;
    235         PropertyValuesHolder pivotX;
    236         PropertyValuesHolder pivotY;
    237         ArrayList<Animator> anims = new ArrayList<Animator>();
    238 
    239         for (int i = 0; i < count; i++) {
    240             KeyguardWidgetFrame child = getWidgetPageAt(i);
    241             float finalAlpha = getAlphaForPage(mScreenCenter, i, true);
    242             float finalOutlineAlpha = getOutlineAlphaForPage(mScreenCenter, i, true);
    243             getTransformForPage(mScreenCenter, i, mTmpTransform);
    244 
    245             boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1);
    246 
    247             ObjectAnimator a;
    248             alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalAlpha);
    249             outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", finalOutlineAlpha);
    250             pivotX = PropertyValuesHolder.ofFloat("pivotX", mTmpTransform[0]);
    251             pivotY = PropertyValuesHolder.ofFloat("pivotY", mTmpTransform[1]);
    252             rotationY = PropertyValuesHolder.ofFloat("rotationY", mTmpTransform[2]);
    253 
    254             if (inVisibleRange) {
    255                 // for the central pages we animate into a rotated state
    256                 a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha,
    257                         pivotX, pivotY, rotationY);
    258             } else {
    259                 a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha);
    260                 a.setInterpolator(mFastFadeInterpolator);
    261             }
    262             anims.add(a);
    263         }
    264 
    265         int duration = REORDERING_ZOOM_IN_OUT_DURATION;
    266         mChildrenTransformsAnimator = new AnimatorSet();
    267         mChildrenTransformsAnimator.playTogether(anims);
    268 
    269         mChildrenTransformsAnimator.setDuration(duration);
    270         mChildrenTransformsAnimator.start();
    271     }
    272 
    273     protected void reorderStarting() {
    274         mViewStateManager.fadeOutSecurity(REORDERING_ZOOM_IN_OUT_DURATION);
    275         animatePagesToNeutral();
    276     }
    277 
    278     protected boolean zoomIn(final Runnable onCompleteRunnable) {
    279         animatePagesToCarousel();
    280         return super.zoomIn(onCompleteRunnable);
    281     }
    282 
    283     @Override
    284     protected void onEndReordering() {
    285         super.onEndReordering();
    286         mViewStateManager.fadeInSecurity(REORDERING_ZOOM_IN_OUT_DURATION);
    287     }
    288 }
    289