KeyguardWidgetPager.java revision 6526fdd7490acc40ce9dbe4ae563821f8867aa0f
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.TimeInterpolator;
19import android.appwidget.AppWidgetHostView;
20import android.content.Context;
21import android.util.AttributeSet;
22import android.view.Gravity;
23import android.view.MotionEvent;
24import android.view.View;
25import android.view.animation.AccelerateInterpolator;
26import android.view.animation.DecelerateInterpolator;
27
28import android.widget.FrameLayout;
29
30import com.android.internal.R;
31
32public class KeyguardWidgetPager extends PagedView {
33    ZInterpolator mZInterpolator = new ZInterpolator(0.5f);
34    private static float CAMERA_DISTANCE = 10000;
35    private static float TRANSITION_SCALE_FACTOR = 0.74f;
36    private static float TRANSITION_PIVOT = 0.65f;
37    private static float TRANSITION_MAX_ROTATION = 30;
38    private static final boolean PERFORM_OVERSCROLL_ROTATION = true;
39    private AccelerateInterpolator mAlphaInterpolator = new AccelerateInterpolator(0.9f);
40    private DecelerateInterpolator mLeftScreenAlphaInterpolator = new DecelerateInterpolator(4);
41
42    public KeyguardWidgetPager(Context context, AttributeSet attrs) {
43        this(context, attrs, 0);
44    }
45
46    public KeyguardWidgetPager(Context context) {
47        this(null, null, 0);
48    }
49
50    public KeyguardWidgetPager(Context context, AttributeSet attrs, int defStyle) {
51        super(context, attrs, defStyle);
52        if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
53            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
54        }
55    }
56
57    /*
58     * We wrap widgets in a special frame which handles drawing the overscroll foreground.
59     */
60    public void addWidget(AppWidgetHostView widget) {
61        KeyguardWidgetFrame frame = new KeyguardWidgetFrame(getContext());
62        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
63                LayoutParams.MATCH_PARENT);
64        lp.gravity = Gravity.CENTER;
65        // The framework adds a default padding to AppWidgetHostView. We don't need this padding
66        // for the Keyguard, so we override it to be 0.
67        widget.setPadding(0,  0, 0, 0);
68        widget.setContentDescription(widget.getAppWidgetInfo().label);
69        frame.addView(widget, lp);
70        addView(frame);
71    }
72
73    protected void onUnhandledTap(MotionEvent ev) {
74        if (getParent() instanceof KeyguardWidgetRegion) {
75            ((KeyguardWidgetRegion) getParent()).showPagingFeedback();
76        }
77    }
78
79    /*
80     * This interpolator emulates the rate at which the perceived scale of an object changes
81     * as its distance from a camera increases. When this interpolator is applied to a scale
82     * animation on a view, it evokes the sense that the object is shrinking due to moving away
83     * from the camera.
84     */
85    static class ZInterpolator implements TimeInterpolator {
86        private float focalLength;
87
88        public ZInterpolator(float foc) {
89            focalLength = foc;
90        }
91
92        public float getInterpolation(float input) {
93            return (1.0f - focalLength / (focalLength + input)) /
94                (1.0f - focalLength / (focalLength + 1.0f));
95        }
96    }
97
98    @Override
99    public String getCurrentPageDescription() {
100        final int nextPageIndex = getNextPage();
101        if (nextPageIndex >= 0 && nextPageIndex < getChildCount()) {
102            KeyguardWidgetFrame frame = (KeyguardWidgetFrame) getChildAt(nextPageIndex);
103            CharSequence title = frame.getChildAt(0).getContentDescription();
104            if (title == null) {
105                title = "";
106            }
107            return mContext.getString(R.string.keyguard_accessibility_widget_changed,
108                    title, nextPageIndex + 1, getChildCount());
109        }
110        return super.getCurrentPageDescription();
111    }
112
113    @Override
114    protected void overScroll(float amount) {
115        acceleratedOverScroll(amount);
116    }
117
118    // In apps customize, we have a scrolling effect which emulates pulling cards off of a stack.
119    @Override
120    protected void screenScrolled(int screenCenter) {
121        super.screenScrolled(screenCenter);
122
123        for (int i = 0; i < getChildCount(); i++) {
124            View v = getPageAt(i);
125            if (v != null) {
126                float scrollProgress = getScrollProgress(screenCenter, v, i);
127
128                float interpolatedProgress =
129                        mZInterpolator.getInterpolation(Math.abs(Math.min(scrollProgress, 0)));
130                float scale = (1 - interpolatedProgress) +
131                        interpolatedProgress * TRANSITION_SCALE_FACTOR;
132                float translationX = Math.min(0, scrollProgress) * v.getMeasuredWidth();
133
134                float alpha;
135
136                if (scrollProgress < 0) {
137                    alpha = scrollProgress < 0 ? mAlphaInterpolator.getInterpolation(
138                        1 - Math.abs(scrollProgress)) : 1.0f;
139                } else {
140                    // On large screens we need to fade the page as it nears its leftmost position
141                    alpha = mLeftScreenAlphaInterpolator.getInterpolation(1 - scrollProgress);
142                }
143
144                v.setCameraDistance(mDensity * CAMERA_DISTANCE);
145                int pageWidth = v.getMeasuredWidth();
146                int pageHeight = v.getMeasuredHeight();
147
148                if (PERFORM_OVERSCROLL_ROTATION) {
149                    if (i == 0 && scrollProgress < 0) {
150                        // Overscroll to the left
151                        v.setPivotX(TRANSITION_PIVOT * pageWidth);
152                        v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress);
153                        if (v instanceof KeyguardWidgetFrame) {
154                            ((KeyguardWidgetFrame) v).setOverScrollAmount(Math.abs(scrollProgress),
155                                    true);
156                        }
157                        scale = 1.0f;
158                        alpha = 1.0f;
159                        // On the first page, we don't want the page to have any lateral motion
160                        translationX = 0;
161                    } else if (i == getChildCount() - 1 && scrollProgress > 0) {
162                        // Overscroll to the right
163                        v.setPivotX((1 - TRANSITION_PIVOT) * pageWidth);
164                        v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress);
165                        scale = 1.0f;
166                        alpha = 1.0f;
167                        if (v instanceof KeyguardWidgetFrame) {
168                            ((KeyguardWidgetFrame) v).setOverScrollAmount(Math.abs(scrollProgress),
169                                    false);
170                        }
171                        // On the last page, we don't want the page to have any lateral motion.
172                        translationX = 0;
173                    } else {
174                        v.setPivotY(pageHeight / 2.0f);
175                        v.setPivotX(pageWidth / 2.0f);
176                        v.setRotationY(0f);
177                        if (v instanceof KeyguardWidgetFrame) {
178                            ((KeyguardWidgetFrame) v).setOverScrollAmount(0, false);
179                        }
180                    }
181                }
182
183                v.setTranslationX(translationX);
184                v.setScaleX(scale);
185                v.setScaleY(scale);
186                v.setAlpha(alpha);
187
188                // If the view has 0 alpha, we set it to be invisible so as to prevent
189                // it from accepting touches
190                if (alpha == 0) {
191                    v.setVisibility(INVISIBLE);
192                } else if (v.getVisibility() != VISIBLE) {
193                    v.setVisibility(VISIBLE);
194                }
195            }
196        }
197    }
198}
199