KeyguardViewStateManager.java revision d51700b3cc6d4c66a33d18348f7c1eb66cd50ac2
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.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    // transport control states
38    static final int TRANSPORT_GONE = 0;
39    static final int TRANSPORT_INVISIBLE = 1;
40    static final int TRANSPORT_VISIBLE = 2;
41
42    private int mTransportState = TRANSPORT_GONE;
43
44    int mLastScrollState = SlidingChallengeLayout.SCROLL_STATE_IDLE;
45
46    // Paged view state
47    private int mPageListeningToSlider = -1;
48    private int mCurrentPage = -1;
49    private int mPageIndexOnPageBeginMoving = -1;
50
51    int mChallengeTop = 0;
52
53    public KeyguardViewStateManager(KeyguardHostView hostView) {
54        mKeyguardHostView = hostView;
55    }
56
57    public void setPagedView(KeyguardWidgetPager pagedView) {
58        mKeyguardWidgetPager = pagedView;
59        updateEdgeSwiping();
60    }
61
62    public void setChallengeLayout(ChallengeLayout layout) {
63        mChallengeLayout = layout;
64        updateEdgeSwiping();
65    }
66
67    private void updateEdgeSwiping() {
68        if (mChallengeLayout != null && mKeyguardWidgetPager != null) {
69            if (mChallengeLayout.isChallengeOverlapping()) {
70                mKeyguardWidgetPager.setOnlyAllowEdgeSwipes(true);
71            } else {
72                mKeyguardWidgetPager.setOnlyAllowEdgeSwipes(false);
73            }
74        }
75    }
76
77    public boolean isChallengeShowing() {
78        if (mChallengeLayout != null) {
79            return mChallengeLayout.isChallengeShowing();
80        }
81        return false;
82    }
83
84    public boolean isChallengeOverlapping() {
85        if (mChallengeLayout != null) {
86            return mChallengeLayout.isChallengeOverlapping();
87        }
88        return false;
89    }
90
91    public void setSecurityViewContainer(KeyguardSecurityView container) {
92        mKeyguardSecurityContainer = container;
93    }
94
95    public void showBouncer(boolean show) {
96        mChallengeLayout.showBouncer();
97    }
98
99    public boolean isBouncing() {
100        return mChallengeLayout.isBouncing();
101    }
102
103    public void fadeOutSecurity(int duration) {
104        ((View) mKeyguardSecurityContainer).animate().alpha(0).setDuration(duration);
105    }
106
107    public void fadeInSecurity(int duration) {
108        ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration);
109    }
110
111    public void onPageBeginMoving() {
112        if (mChallengeLayout.isChallengeOverlapping() &&
113                mChallengeLayout instanceof SlidingChallengeLayout) {
114            SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
115            scl.fadeOutChallenge();
116            mPageIndexOnPageBeginMoving = mKeyguardWidgetPager.getCurrentPage();
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    private int getChallengeTopRelativeToFrame(KeyguardWidgetFrame frame, int top) {
172        mTmpPoint[0] = 0;
173        mTmpPoint[1] = top;
174        mapPoint((View) mChallengeLayout, frame, mTmpPoint);
175        return mTmpPoint[1];
176    }
177
178    /**
179     * Simple method to map a point from one view's coordinates to another's. Note: this method
180     * doesn't account for transforms, so if the views will be transformed, this should not be used.
181     *
182     * @param fromView The view to which the point is relative
183     * @param toView The view into which the point should be mapped
184     * @param pt The point
185     */
186    private void mapPoint(View fromView, View toView, int pt[]) {
187        fromView.getLocationInWindow(mTmpLoc);
188
189        int x = mTmpLoc[0];
190        int y = mTmpLoc[1];
191
192        toView.getLocationInWindow(mTmpLoc);
193        int vX = mTmpLoc[0];
194        int vY = mTmpLoc[1];
195
196        pt[0] += x - vX;
197        pt[1] += y - vY;
198    }
199
200    @Override
201    public void onScrollStateChanged(int scrollState) {
202        if (mKeyguardWidgetPager == null || mChallengeLayout == null) return;
203
204        boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping();
205
206        if (scrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
207            KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
208            if (frame == null) return;
209
210            if (!challengeOverlapping) {
211                if (!mKeyguardWidgetPager.isPageMoving()) {
212                    frame.resetSize();
213                } else {
214                    mKeyguardWidgetPager.setWidgetToResetOnPageFadeOut(mPageListeningToSlider);
215                }
216            }
217            if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
218                frame.hideFrame(this);
219            }
220            updateEdgeSwiping();
221
222            if (mChallengeLayout.isChallengeShowing()) {
223                mKeyguardSecurityContainer.onResume();
224            } else {
225                mKeyguardSecurityContainer.onPause();
226            }
227            mPageListeningToSlider = -1;
228        } else if (mLastScrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
229            // Whether dragging or settling, if the last state was idle, we use this signal
230            // to update the current page who will receive events from the sliding challenge.
231            // We resize the frame as appropriate.
232            mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
233            KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
234            if (frame == null) return;
235
236            // Skip showing the frame and shrinking the widget if we are
237            if (!mChallengeLayout.isBouncing()) {
238                if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
239                    frame.showFrame(this);
240                }
241
242                // As soon as the security begins sliding, the widget becomes small (if it wasn't
243                // small to begin with).
244                if (!frame.isSmall()) {
245                    // We need to fetch the final page, in case the pages are in motion.
246                    mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
247                    frame.shrinkWidget();
248                }
249            } else {
250                if (!frame.isSmall()) {
251                    // We need to fetch the final page, in case the pages are in motion.
252                    mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
253                }
254            }
255
256            // View is on the move.  Pause the security view until it completes.
257            mKeyguardSecurityContainer.onPause();
258        }
259        mLastScrollState = scrollState;
260    }
261
262    @Override
263    public void onScrollPositionChanged(float scrollPosition, int challengeTop) {
264        mChallengeTop = challengeTop;
265        KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
266        if (frame != null && !mKeyguardWidgetPager.isPageMoving()) {
267            frame.adjustFrame(getChallengeTopRelativeToFrame(frame, mChallengeTop));
268        }
269    }
270
271    private Runnable mHideHintsRunnable = new Runnable() {
272        @Override
273        public void run() {
274            if (mKeyguardWidgetPager != null) {
275                mKeyguardWidgetPager.hideOutlinesAndSidePages();
276            }
277        }
278    };
279
280    public void showUsabilityHints() {
281        mMainQueue.postDelayed( new Runnable() {
282            @Override
283            public void run() {
284                mKeyguardSecurityContainer.showUsabilityHint();
285            }
286        } , SCREEN_ON_RING_HINT_DELAY);
287        mKeyguardWidgetPager.showInitialPageHints();
288        if (mHideHintsRunnable != null) {
289            mMainQueue.postDelayed(mHideHintsRunnable, SCREEN_ON_HINT_DURATION);
290        }
291    }
292
293    public void setTransportState(int state) {
294        mTransportState = state;
295    }
296
297    public int getTransportState() {
298        return mTransportState;
299    }
300
301    // ChallengeLayout.OnBouncerStateChangedListener
302    @Override
303    public void onBouncerStateChanged(boolean bouncerActive) {
304        if (bouncerActive) {
305            mKeyguardWidgetPager.zoomOutToBouncer();
306        } else {
307            mKeyguardWidgetPager.zoomInFromBouncer();
308        }
309    }
310}
311