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