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