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