KeyguardViewStateManager.java revision c162dd049084681711526b219ea997aa23f5ad98
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.keyguard;
17
18import android.os.Handler;
19import android.os.Looper;
20import android.util.Log;
21import android.view.View;
22
23public class KeyguardViewStateManager implements
24        SlidingChallengeLayout.OnChallengeScrolledListener,
25        ChallengeLayout.OnBouncerStateChangedListener {
26
27    private static final String TAG = "KeyguardViewStateManager";
28    private KeyguardWidgetPager mKeyguardWidgetPager;
29    private ChallengeLayout mChallengeLayout;
30    private KeyguardHostView mKeyguardHostView;
31    private int[] mTmpPoint = new int[2];
32    private int[] mTmpLoc = new int[2];
33
34    private KeyguardSecurityView mKeyguardSecurityContainer;
35    private static final int SCREEN_ON_HINT_DURATION = 1000;
36    private static final int SCREEN_ON_RING_HINT_DELAY = 300;
37    private static final boolean SHOW_INITIAL_PAGE_HINTS = false;
38    Handler mMainQueue = new Handler(Looper.myLooper());
39
40    int mLastScrollState = SlidingChallengeLayout.SCROLL_STATE_IDLE;
41
42    // Paged view state
43    private int mPageListeningToSlider = -1;
44    private int mCurrentPage = -1;
45    private int mPageIndexOnPageBeginMoving = -1;
46
47    int mChallengeTop = 0;
48
49    public KeyguardViewStateManager(KeyguardHostView hostView) {
50        mKeyguardHostView = hostView;
51    }
52
53    public void setPagedView(KeyguardWidgetPager pagedView) {
54        mKeyguardWidgetPager = pagedView;
55        updateEdgeSwiping();
56    }
57
58    public void setChallengeLayout(ChallengeLayout layout) {
59        mChallengeLayout = layout;
60        updateEdgeSwiping();
61    }
62
63    private void updateEdgeSwiping() {
64        if (mChallengeLayout != null && mKeyguardWidgetPager != null) {
65            if (mChallengeLayout.isChallengeOverlapping()) {
66                mKeyguardWidgetPager.setOnlyAllowEdgeSwipes(true);
67            } else {
68                mKeyguardWidgetPager.setOnlyAllowEdgeSwipes(false);
69            }
70        }
71    }
72
73    public boolean isChallengeShowing() {
74        if (mChallengeLayout != null) {
75            return mChallengeLayout.isChallengeShowing();
76        }
77        return false;
78    }
79
80    public boolean isChallengeOverlapping() {
81        if (mChallengeLayout != null) {
82            return mChallengeLayout.isChallengeOverlapping();
83        }
84        return false;
85    }
86
87    public void setSecurityViewContainer(KeyguardSecurityView container) {
88        mKeyguardSecurityContainer = container;
89    }
90
91    public void showBouncer(boolean show) {
92        CharSequence what = mKeyguardHostView.getContext().getResources().getText(
93                show ? R.string.keyguard_accessibility_show_bouncer
94                        : R.string.keyguard_accessibility_hide_bouncer);
95        mKeyguardHostView.announceForAccessibility(what);
96        mKeyguardHostView.announceCurrentSecurityMethod();
97        mChallengeLayout.showBouncer();
98    }
99
100    public boolean isBouncing() {
101        return mChallengeLayout.isBouncing();
102    }
103
104    public void fadeOutSecurity(int duration) {
105        ((View) mKeyguardSecurityContainer).animate().alpha(0f).setDuration(duration).start();
106    }
107
108    public void fadeInSecurity(int duration) {
109        ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration).start();
110    }
111
112    public void onPageBeginMoving() {
113        if (mChallengeLayout.isChallengeOverlapping() &&
114                mChallengeLayout instanceof SlidingChallengeLayout) {
115            SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
116            if (!mKeyguardWidgetPager.isWarping()) {
117                scl.fadeOutChallenge();
118            }
119            mPageIndexOnPageBeginMoving = mKeyguardWidgetPager.getCurrentPage();
120        }
121        // We use mAppWidgetToShow to show a particular widget after you add it--
122        // once the user swipes a page we clear that behavior
123        if (mKeyguardHostView != null) {
124            mKeyguardHostView.clearAppWidgetToShow();
125            mKeyguardHostView.setOnDismissAction(null);
126        }
127        if (mHideHintsRunnable != null) {
128            mMainQueue.removeCallbacks(mHideHintsRunnable);
129            mHideHintsRunnable = null;
130        }
131    }
132
133    public void onPageEndMoving() {
134        mPageIndexOnPageBeginMoving = -1;
135    }
136
137    public void onPageSwitching(View newPage, int newPageIndex) {
138        if (mKeyguardWidgetPager != null && mChallengeLayout instanceof SlidingChallengeLayout) {
139            boolean isCameraPage = newPage instanceof CameraWidgetFrame;
140            SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
141            scl.setChallengeInteractive(!isCameraPage);
142            if (isCameraPage) scl.fadeOutChallenge();
143        }
144
145        // If the page we're settling to is the same as we started on, and the action of
146        // moving the page hid the security, we restore it immediately.
147        if (mPageIndexOnPageBeginMoving == mKeyguardWidgetPager.getNextPage() &&
148                mChallengeLayout instanceof SlidingChallengeLayout) {
149            SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
150            scl.fadeInChallenge();
151            mKeyguardWidgetPager.setWidgetToResetOnPageFadeOut(-1);
152        }
153        mPageIndexOnPageBeginMoving = -1;
154    }
155
156    public void onPageSwitched(View newPage, int newPageIndex) {
157        // Reset the previous page size and ensure the current page is sized appropriately.
158        // We only modify the page state if it is not currently under control by the slider.
159        // This prevents conflicts.
160
161        // If the page hasn't switched, don't bother with any of this
162        if (mCurrentPage == newPageIndex) return;
163
164        if (mKeyguardWidgetPager != null && mChallengeLayout != null) {
165            KeyguardWidgetFrame prevPage = mKeyguardWidgetPager.getWidgetPageAt(mCurrentPage);
166            if (prevPage != null && mCurrentPage != mPageListeningToSlider && mCurrentPage
167                    != mKeyguardWidgetPager.getWidgetToResetOnPageFadeOut()) {
168                prevPage.resetSize();
169            }
170
171            KeyguardWidgetFrame newCurPage = mKeyguardWidgetPager.getWidgetPageAt(newPageIndex);
172            boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping();
173            if (challengeOverlapping && !newCurPage.isSmall()
174                    && mPageListeningToSlider != newPageIndex) {
175                newCurPage.shrinkWidget();
176            }
177        }
178
179        mCurrentPage = newPageIndex;
180    }
181
182    public void onPageBeginWarp() {
183        fadeOutSecurity(SlidingChallengeLayout.CHALLENGE_FADE_OUT_DURATION);
184        View frame = mKeyguardWidgetPager.getPageAt(mKeyguardWidgetPager.getPageWarpIndex());
185        ((KeyguardWidgetFrame)frame).showFrame(this);
186    }
187
188    public void onPageEndWarp() {
189        fadeInSecurity(SlidingChallengeLayout.CHALLENGE_FADE_IN_DURATION);
190        View frame = mKeyguardWidgetPager.getPageAt(mKeyguardWidgetPager.getPageWarpIndex());
191        ((KeyguardWidgetFrame)frame).hideFrame(this);
192    }
193
194    private int getChallengeTopRelativeToFrame(KeyguardWidgetFrame frame, int top) {
195        mTmpPoint[0] = 0;
196        mTmpPoint[1] = top;
197        mapPoint((View) mChallengeLayout, frame, mTmpPoint);
198        return mTmpPoint[1];
199    }
200
201    /**
202     * Simple method to map a point from one view's coordinates to another's. Note: this method
203     * doesn't account for transforms, so if the views will be transformed, this should not be used.
204     *
205     * @param fromView The view to which the point is relative
206     * @param toView The view into which the point should be mapped
207     * @param pt The point
208     */
209    private void mapPoint(View fromView, View toView, int pt[]) {
210        fromView.getLocationInWindow(mTmpLoc);
211
212        int x = mTmpLoc[0];
213        int y = mTmpLoc[1];
214
215        toView.getLocationInWindow(mTmpLoc);
216        int vX = mTmpLoc[0];
217        int vY = mTmpLoc[1];
218
219        pt[0] += x - vX;
220        pt[1] += y - vY;
221    }
222
223    private void userActivity() {
224        if (mKeyguardHostView != null) {
225            mKeyguardHostView.onUserActivityTimeoutChanged();
226            mKeyguardHostView.userActivity();
227        }
228    }
229
230    @Override
231    public void onScrollStateChanged(int scrollState) {
232        if (mKeyguardWidgetPager == null || mChallengeLayout == null) return;
233
234        boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping();
235
236        if (scrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
237            KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
238            if (frame == null) return;
239
240            if (!challengeOverlapping) {
241                if (!mKeyguardWidgetPager.isPageMoving()) {
242                    frame.resetSize();
243                    userActivity();
244                } else {
245                    mKeyguardWidgetPager.setWidgetToResetOnPageFadeOut(mPageListeningToSlider);
246                }
247            }
248            if (frame.isSmall()) {
249                // This is to make sure that if the scroller animation gets cut off midway
250                // that the frame doesn't stay in a partial down position.
251                frame.setFrameHeight(frame.getSmallFrameHeight());
252            }
253            if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
254                frame.hideFrame(this);
255            }
256            updateEdgeSwiping();
257
258            if (mChallengeLayout.isChallengeShowing()) {
259                mKeyguardSecurityContainer.onResume(KeyguardSecurityView.VIEW_REVEALED);
260            } else {
261                mKeyguardSecurityContainer.onPause();
262            }
263            mPageListeningToSlider = -1;
264        } else if (mLastScrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
265            // Whether dragging or settling, if the last state was idle, we use this signal
266            // to update the current page who will receive events from the sliding challenge.
267            // We resize the frame as appropriate.
268            mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
269            KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
270            if (frame == null) return;
271
272            // Skip showing the frame and shrinking the widget if we are
273            if (!mChallengeLayout.isBouncing()) {
274                if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
275                    frame.showFrame(this);
276                }
277
278                // As soon as the security begins sliding, the widget becomes small (if it wasn't
279                // small to begin with).
280                if (!frame.isSmall()) {
281                    // We need to fetch the final page, in case the pages are in motion.
282                    mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
283                    frame.shrinkWidget(false);
284                }
285            } else {
286                if (!frame.isSmall()) {
287                    // We need to fetch the final page, in case the pages are in motion.
288                    mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
289                }
290            }
291
292            // View is on the move.  Pause the security view until it completes.
293            mKeyguardSecurityContainer.onPause();
294        }
295        mLastScrollState = scrollState;
296    }
297
298    @Override
299    public void onScrollPositionChanged(float scrollPosition, int challengeTop) {
300        mChallengeTop = challengeTop;
301        KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
302        if (frame != null && mLastScrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
303            frame.adjustFrame(getChallengeTopRelativeToFrame(frame, mChallengeTop));
304        }
305    }
306
307    private Runnable mHideHintsRunnable = new Runnable() {
308        @Override
309        public void run() {
310            if (mKeyguardWidgetPager != null) {
311                mKeyguardWidgetPager.hideOutlinesAndSidePages();
312            }
313        }
314    };
315
316    public void showUsabilityHints() {
317        mMainQueue.postDelayed( new Runnable() {
318            @Override
319            public void run() {
320                mKeyguardSecurityContainer.showUsabilityHint();
321            }
322        } , SCREEN_ON_RING_HINT_DELAY);
323        if (SHOW_INITIAL_PAGE_HINTS) {
324            mKeyguardWidgetPager.showInitialPageHints();
325        }
326        if (mHideHintsRunnable != null) {
327            mMainQueue.postDelayed(mHideHintsRunnable, SCREEN_ON_HINT_DURATION);
328        }
329    }
330
331    // ChallengeLayout.OnBouncerStateChangedListener
332    @Override
333    public void onBouncerStateChanged(boolean bouncerActive) {
334        if (bouncerActive) {
335            mKeyguardWidgetPager.zoomOutToBouncer();
336        } else {
337            mKeyguardWidgetPager.zoomInFromBouncer();
338            if (mKeyguardHostView != null) {
339                mKeyguardHostView.setOnDismissAction(null);
340            }
341        }
342    }
343}
344