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