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