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