KeyguardWidgetCarousel.java revision 934d0835c8bae6d8aacf4d661b7134691d8e241b
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 */
16package com.android.internal.policy.impl.keyguard;
17
18import android.animation.Animator;
19import android.animation.AnimatorListenerAdapter;
20import android.animation.AnimatorSet;
21import android.animation.ObjectAnimator;
22import android.animation.PropertyValuesHolder;
23import android.content.Context;
24import android.util.AttributeSet;
25import android.view.View;
26import android.view.animation.AccelerateInterpolator;
27import android.view.animation.DecelerateInterpolator;
28import android.view.animation.Interpolator;
29
30import java.util.ArrayList;
31
32import com.android.internal.R;
33
34public class KeyguardWidgetCarousel extends KeyguardWidgetPager {
35
36    private float mAdjacentPagesAngle;
37    private static float MAX_SCROLL_PROGRESS = 1.3f;
38    private static float CAMERA_DISTANCE = 10000;
39    protected AnimatorSet mChildrenTransformsAnimator;
40    float[] mTmpTransform = new float[3];
41
42    public KeyguardWidgetCarousel(Context context, AttributeSet attrs) {
43        this(context, attrs, 0);
44    }
45
46    public KeyguardWidgetCarousel(Context context) {
47        this(context, null, 0);
48    }
49
50    public KeyguardWidgetCarousel(Context context, AttributeSet attrs, int defStyle) {
51        super(context, attrs, defStyle);
52        mAdjacentPagesAngle = context.getResources().getInteger(R.integer.kg_carousel_angle);
53    }
54
55    protected float getMaxScrollProgress() {
56        return MAX_SCROLL_PROGRESS;
57    }
58
59    public float getAlphaForPage(int screenCenter, int index) {
60        View child = getChildAt(index);
61        if (child == null) return 0f;
62
63        float scrollProgress = getScrollProgress(screenCenter, child, index);
64        if (!isOverScrollChild(index, scrollProgress)) {
65            scrollProgress = getBoundedScrollProgress(screenCenter, child, index);
66            float alpha = 1.0f - 1.0f * Math.abs(scrollProgress / MAX_SCROLL_PROGRESS);
67            return alpha;
68        } else {
69            return 1.0f;
70        }
71    }
72
73    private void updatePageAlphaValues(int screenCenter) {
74        if (mChildrenOutlineFadeAnimation != null) {
75            mChildrenOutlineFadeAnimation.cancel();
76            mChildrenOutlineFadeAnimation = null;
77        }
78        if (!isReordering(false)) {
79            for (int i = 0; i < getChildCount(); i++) {
80                KeyguardWidgetFrame child = getWidgetPageAt(i);
81                if (child != null) {
82                    child.setBackgroundAlpha(getOutlineAlphaForPage(screenCenter, i));
83                    child.setContentAlpha(getAlphaForPage(screenCenter, i));
84                }
85            }
86        }
87    }
88
89    public void showInitialPageHints() {
90        int count = getChildCount();
91        for (int i = 0; i < count; i++) {
92            KeyguardWidgetFrame child = getWidgetPageAt(i);
93            if (i >= mCurrentPage - 1 && i <= mCurrentPage + 1) {
94                child.fadeFrame(this, true, KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER,
95                        CHILDREN_OUTLINE_FADE_IN_DURATION);
96            }
97        }
98    }
99
100    @Override
101    protected void screenScrolled(int screenCenter) {
102        mScreenCenter = screenCenter;
103        updatePageAlphaValues(screenCenter);
104        if (isReordering(false)) return;
105        for (int i = 0; i < getChildCount(); i++) {
106            KeyguardWidgetFrame v = getWidgetPageAt(i);
107            float scrollProgress = getScrollProgress(screenCenter, v, i);
108            float boundedProgress = getBoundedScrollProgress(screenCenter, v, i);
109            if (v == mDragView || v == null) continue;
110            v.setCameraDistance(CAMERA_DISTANCE);
111
112            if (isOverScrollChild(i, scrollProgress)) {
113                v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress);
114                v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0);
115            } else {
116                int width = v.getMeasuredWidth();
117                float pivotX = (width / 2f) + boundedProgress * (width / 2f);
118                float pivotY = v.getMeasuredHeight() / 2;
119                float rotationY = - mAdjacentPagesAngle * boundedProgress;
120                v.setPivotX(pivotX);
121                v.setPivotY(pivotY);
122                v.setRotationY(rotationY);
123                v.setOverScrollAmount(0f, false);
124            }
125            float alpha = v.getAlpha();
126            // If the view has 0 alpha, we set it to be invisible so as to prevent
127            // it from accepting touches
128            if (alpha == 0) {
129                v.setVisibility(INVISIBLE);
130            } else if (v.getVisibility() != VISIBLE) {
131                v.setVisibility(VISIBLE);
132            }
133        }
134    }
135
136    void animatePagesToNeutral() {
137        if (mChildrenTransformsAnimator != null) {
138            mChildrenTransformsAnimator.cancel();
139            mChildrenTransformsAnimator = null;
140        }
141
142        int count = getChildCount();
143        PropertyValuesHolder alpha;
144        PropertyValuesHolder outlineAlpha;
145        PropertyValuesHolder rotationY;
146        ArrayList<Animator> anims = new ArrayList<Animator>();
147
148        for (int i = 0; i < count; i++) {
149            KeyguardWidgetFrame child = getWidgetPageAt(i);
150            boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1);
151            if (!inVisibleRange) {
152                child.setRotationY(0f);
153            }
154            alpha = PropertyValuesHolder.ofFloat("contentAlpha", 1.0f);
155            outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha",
156                    KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
157            rotationY = PropertyValuesHolder.ofFloat("rotationY", 0f);
158            ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha, rotationY);
159            child.setVisibility(VISIBLE);
160            if (!inVisibleRange) {
161                a.setInterpolator(mSlowFadeInterpolator);
162            }
163            anims.add(a);
164        }
165
166        int duration = REORDERING_ZOOM_IN_OUT_DURATION;
167        mChildrenTransformsAnimator = new AnimatorSet();
168        mChildrenTransformsAnimator.playTogether(anims);
169
170        mChildrenTransformsAnimator.setDuration(duration);
171        mChildrenTransformsAnimator.start();
172    }
173
174    private void getTransformForPage(int screenCenter, int index, float[] transform) {
175        View child = getChildAt(index);
176        float boundedProgress = getBoundedScrollProgress(screenCenter, child, index);
177        float rotationY = - mAdjacentPagesAngle * boundedProgress;
178        int width = child.getMeasuredWidth();
179        float pivotX = (width / 2f) + boundedProgress * (width / 2f);
180        float pivotY = child.getMeasuredHeight() / 2;
181
182        transform[0] = pivotX;
183        transform[1] = pivotY;
184        transform[2] = rotationY;
185    }
186
187    Interpolator mFastFadeInterpolator = new Interpolator() {
188        Interpolator mInternal = new DecelerateInterpolator(1.5f);
189        float mFactor = 2.5f;
190        @Override
191        public float getInterpolation(float input) {
192            return mInternal.getInterpolation(Math.min(mFactor * input, 1f));
193        }
194    };
195
196    Interpolator mSlowFadeInterpolator = new Interpolator() {
197        Interpolator mInternal = new AccelerateInterpolator(1.5f);
198        float mFactor = 1.3f;
199        @Override
200        public float getInterpolation(float input) {
201            input -= (1 - 1 / mFactor);
202            input = mFactor * Math.max(input, 0f);
203            return mInternal.getInterpolation(input);
204        }
205    };
206
207    void animatePagesToCarousel() {
208        if (mChildrenTransformsAnimator != null) {
209            mChildrenTransformsAnimator.cancel();
210            mChildrenTransformsAnimator = null;
211        }
212
213        int count = getChildCount();
214        PropertyValuesHolder alpha;
215        PropertyValuesHolder outlineAlpha;
216        PropertyValuesHolder rotationY;
217        PropertyValuesHolder pivotX;
218        PropertyValuesHolder pivotY;
219        ArrayList<Animator> anims = new ArrayList<Animator>();
220
221        for (int i = 0; i < count; i++) {
222            KeyguardWidgetFrame child = getWidgetPageAt(i);
223            float finalAlpha = getAlphaForPage(mScreenCenter, i);
224            float finalOutlineAlpha = getOutlineAlphaForPage(mScreenCenter, i);
225            getTransformForPage(mScreenCenter, i, mTmpTransform);
226
227            boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1);
228
229            ObjectAnimator a;
230            alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalAlpha);
231            outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", finalOutlineAlpha);
232            pivotX = PropertyValuesHolder.ofFloat("pivotX", mTmpTransform[0]);
233            pivotY = PropertyValuesHolder.ofFloat("pivotY", mTmpTransform[1]);
234            rotationY = PropertyValuesHolder.ofFloat("rotationY", mTmpTransform[2]);
235
236            if (inVisibleRange) {
237                // for the central pages we animate into a rotated state
238                a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha,
239                        pivotX, pivotY, rotationY);
240            } else {
241                a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha);
242                a.setInterpolator(mFastFadeInterpolator);
243            }
244            anims.add(a);
245        }
246
247        int duration = REORDERING_ZOOM_IN_OUT_DURATION;
248        mChildrenTransformsAnimator = new AnimatorSet();
249        mChildrenTransformsAnimator.playTogether(anims);
250
251        mChildrenTransformsAnimator.setDuration(duration);
252        mChildrenTransformsAnimator.start();
253    }
254
255    protected void reorderStarting() {
256        mViewStateManager.fadeOutSecurity(REORDERING_ZOOM_IN_OUT_DURATION);
257        animatePagesToNeutral();
258    }
259
260    protected boolean zoomIn(final Runnable onCompleteRunnable) {
261        animatePagesToCarousel();
262        return super.zoomIn(onCompleteRunnable);
263    }
264
265    @Override
266    protected void onEndReordering() {
267        super.onEndReordering();
268        mViewStateManager.fadeInSecurity(REORDERING_ZOOM_IN_OUT_DURATION);
269    }
270}
271