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