blob: e47edf3021e9d1f8534b9f6dff00fd184d7ffb13 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.keyguard;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
public class KeyguardViewStateManager implements
SlidingChallengeLayout.OnChallengeScrolledListener,
ChallengeLayout.OnBouncerStateChangedListener {
private static final String TAG = "KeyguardViewStateManager";
private KeyguardWidgetPager mKeyguardWidgetPager;
private ChallengeLayout mChallengeLayout;
private KeyguardHostView mKeyguardHostView;
private int[] mTmpPoint = new int[2];
private int[] mTmpLoc = new int[2];
private KeyguardSecurityView mKeyguardSecurityContainer;
private static final int SCREEN_ON_HINT_DURATION = 1000;
private static final int SCREEN_ON_RING_HINT_DELAY = 300;
private static final boolean SHOW_INITIAL_PAGE_HINTS = false;
Handler mMainQueue = new Handler(Looper.myLooper());
int mLastScrollState = SlidingChallengeLayout.SCROLL_STATE_IDLE;
// Paged view state
private int mPageListeningToSlider = -1;
private int mCurrentPage = -1;
private int mPageIndexOnPageBeginMoving = -1;
int mChallengeTop = 0;
private final AnimatorListener mPauseListener = new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
mKeyguardSecurityContainer.onPause();
}
};
private final AnimatorListener mResumeListener = new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
if (((View)mKeyguardSecurityContainer).isShown()) {
mKeyguardSecurityContainer.onResume(0);
}
}
};
public KeyguardViewStateManager(KeyguardHostView hostView) {
mKeyguardHostView = hostView;
}
public void setPagedView(KeyguardWidgetPager pagedView) {
mKeyguardWidgetPager = pagedView;
updateEdgeSwiping();
}
public void setChallengeLayout(ChallengeLayout layout) {
mChallengeLayout = layout;
updateEdgeSwiping();
}
private void updateEdgeSwiping() {
if (mChallengeLayout != null && mKeyguardWidgetPager != null) {
if (mChallengeLayout.isChallengeOverlapping()) {
mKeyguardWidgetPager.setOnlyAllowEdgeSwipes(true);
} else {
mKeyguardWidgetPager.setOnlyAllowEdgeSwipes(false);
}
}
}
public boolean isChallengeShowing() {
if (mChallengeLayout != null) {
return mChallengeLayout.isChallengeShowing();
}
return false;
}
public boolean isChallengeOverlapping() {
if (mChallengeLayout != null) {
return mChallengeLayout.isChallengeOverlapping();
}
return false;
}
public void setSecurityViewContainer(KeyguardSecurityView container) {
mKeyguardSecurityContainer = container;
}
public void showBouncer(boolean show) {
mChallengeLayout.showBouncer();
}
public boolean isBouncing() {
return mChallengeLayout.isBouncing();
}
public void fadeOutSecurity(int duration) {
((View) mKeyguardSecurityContainer).animate().alpha(0f).setDuration(duration)
.setListener(mPauseListener);
}
public void fadeInSecurity(int duration) {
((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration)
.setListener(mResumeListener);
}
public void onPageBeginMoving() {
if (mChallengeLayout.isChallengeOverlapping() &&
mChallengeLayout instanceof SlidingChallengeLayout) {
SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
scl.fadeOutChallenge();
mPageIndexOnPageBeginMoving = mKeyguardWidgetPager.getCurrentPage();
}
// We use mAppWidgetToShow to show a particular widget after you add it--
// once the user swipes a page we clear that behavior
if (mKeyguardHostView != null) {
mKeyguardHostView.clearAppWidgetToShow();
mKeyguardHostView.setOnDismissAction(null);
}
if (mHideHintsRunnable != null) {
mMainQueue.removeCallbacks(mHideHintsRunnable);
mHideHintsRunnable = null;
}
}
public void onPageEndMoving() {
mPageIndexOnPageBeginMoving = -1;
}
public void onPageSwitching(View newPage, int newPageIndex) {
if (mKeyguardWidgetPager != null && mChallengeLayout instanceof SlidingChallengeLayout) {
boolean isCameraPage = newPage instanceof CameraWidgetFrame;
if (isCameraPage) {
CameraWidgetFrame camera = (CameraWidgetFrame) newPage;
camera.setUseFastTransition(mKeyguardWidgetPager.isWarping());
}
SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
scl.setChallengeInteractive(!isCameraPage);
final int currentFlags = mKeyguardWidgetPager.getSystemUiVisibility();
final int newFlags = isCameraPage ? (currentFlags | View.STATUS_BAR_DISABLE_SEARCH)
: (currentFlags & ~View.STATUS_BAR_DISABLE_SEARCH);
mKeyguardWidgetPager.setSystemUiVisibility(newFlags);
}
// If the page we're settling to is the same as we started on, and the action of
// moving the page hid the security, we restore it immediately.
if (mPageIndexOnPageBeginMoving == mKeyguardWidgetPager.getNextPage() &&
mChallengeLayout instanceof SlidingChallengeLayout) {
SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
scl.fadeInChallenge();
mKeyguardWidgetPager.setWidgetToResetOnPageFadeOut(-1);
}
mPageIndexOnPageBeginMoving = -1;
}
public void onPageSwitched(View newPage, int newPageIndex) {
// Reset the previous page size and ensure the current page is sized appropriately.
// We only modify the page state if it is not currently under control by the slider.
// This prevents conflicts.
// If the page hasn't switched, don't bother with any of this
if (mCurrentPage == newPageIndex) return;
if (mKeyguardWidgetPager != null && mChallengeLayout != null) {
KeyguardWidgetFrame prevPage = mKeyguardWidgetPager.getWidgetPageAt(mCurrentPage);
if (prevPage != null && mCurrentPage != mPageListeningToSlider && mCurrentPage
!= mKeyguardWidgetPager.getWidgetToResetOnPageFadeOut()) {
prevPage.resetSize();
}
KeyguardWidgetFrame newCurPage = mKeyguardWidgetPager.getWidgetPageAt(newPageIndex);
boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping();
if (challengeOverlapping && !newCurPage.isSmall()
&& mPageListeningToSlider != newPageIndex) {
newCurPage.shrinkWidget(true);
}
}
mCurrentPage = newPageIndex;
}
public void onPageBeginWarp() {
fadeOutSecurity(SlidingChallengeLayout.CHALLENGE_FADE_OUT_DURATION);
View frame = mKeyguardWidgetPager.getPageAt(mKeyguardWidgetPager.getPageWarpIndex());
((KeyguardWidgetFrame)frame).showFrame(this);
}
public void onPageEndWarp() {
fadeInSecurity(SlidingChallengeLayout.CHALLENGE_FADE_IN_DURATION);
View frame = mKeyguardWidgetPager.getPageAt(mKeyguardWidgetPager.getPageWarpIndex());
((KeyguardWidgetFrame)frame).hideFrame(this);
}
private int getChallengeTopRelativeToFrame(KeyguardWidgetFrame frame, int top) {
mTmpPoint[0] = 0;
mTmpPoint[1] = top;
mapPoint((View) mChallengeLayout, frame, mTmpPoint);
return mTmpPoint[1];
}
/**
* Simple method to map a point from one view's coordinates to another's. Note: this method
* doesn't account for transforms, so if the views will be transformed, this should not be used.
*
* @param fromView The view to which the point is relative
* @param toView The view into which the point should be mapped
* @param pt The point
*/
private void mapPoint(View fromView, View toView, int pt[]) {
fromView.getLocationInWindow(mTmpLoc);
int x = mTmpLoc[0];
int y = mTmpLoc[1];
toView.getLocationInWindow(mTmpLoc);
int vX = mTmpLoc[0];
int vY = mTmpLoc[1];
pt[0] += x - vX;
pt[1] += y - vY;
}
private void userActivity() {
if (mKeyguardHostView != null) {
mKeyguardHostView.onUserActivityTimeoutChanged();
mKeyguardHostView.userActivity();
}
}
@Override
public void onScrollStateChanged(int scrollState) {
if (mKeyguardWidgetPager == null || mChallengeLayout == null) return;
boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping();
if (scrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
if (frame == null) return;
if (!challengeOverlapping) {
if (!mKeyguardWidgetPager.isPageMoving()) {
frame.resetSize();
userActivity();
} else {
mKeyguardWidgetPager.setWidgetToResetOnPageFadeOut(mPageListeningToSlider);
}
}
if (frame.isSmall()) {
// This is to make sure that if the scroller animation gets cut off midway
// that the frame doesn't stay in a partial down position.
frame.setFrameHeight(frame.getSmallFrameHeight());
}
if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
frame.hideFrame(this);
}
updateEdgeSwiping();
if (mChallengeLayout.isChallengeShowing()) {
mKeyguardSecurityContainer.onResume(KeyguardSecurityView.VIEW_REVEALED);
} else {
mKeyguardSecurityContainer.onPause();
}
mPageListeningToSlider = -1;
} else if (mLastScrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
// Whether dragging or settling, if the last state was idle, we use this signal
// to update the current page who will receive events from the sliding challenge.
// We resize the frame as appropriate.
mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
if (frame == null) return;
// Skip showing the frame and shrinking the widget if we are
if (!mChallengeLayout.isBouncing()) {
if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
frame.showFrame(this);
}
// As soon as the security begins sliding, the widget becomes small (if it wasn't
// small to begin with).
if (!frame.isSmall()) {
// We need to fetch the final page, in case the pages are in motion.
mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
frame.shrinkWidget(false);
}
} else {
if (!frame.isSmall()) {
// We need to fetch the final page, in case the pages are in motion.
mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
}
}
// View is on the move. Pause the security view until it completes.
mKeyguardSecurityContainer.onPause();
}
mLastScrollState = scrollState;
}
@Override
public void onScrollPositionChanged(float scrollPosition, int challengeTop) {
mChallengeTop = challengeTop;
KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
if (frame != null && mLastScrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
frame.adjustFrame(getChallengeTopRelativeToFrame(frame, mChallengeTop));
}
}
private Runnable mHideHintsRunnable = new Runnable() {
@Override
public void run() {
if (mKeyguardWidgetPager != null) {
mKeyguardWidgetPager.hideOutlinesAndSidePages();
}
}
};
public void showUsabilityHints() {
mMainQueue.postDelayed( new Runnable() {
@Override
public void run() {
mKeyguardSecurityContainer.showUsabilityHint();
}
} , SCREEN_ON_RING_HINT_DELAY);
if (SHOW_INITIAL_PAGE_HINTS) {
mKeyguardWidgetPager.showInitialPageHints();
}
if (mHideHintsRunnable != null) {
mMainQueue.postDelayed(mHideHintsRunnable, SCREEN_ON_HINT_DURATION);
}
}
// ChallengeLayout.OnBouncerStateChangedListener
@Override
public void onBouncerStateChanged(boolean bouncerActive) {
if (bouncerActive) {
mKeyguardWidgetPager.zoomOutToBouncer();
} else {
mKeyguardWidgetPager.zoomInFromBouncer();
if (mKeyguardHostView != null) {
mKeyguardHostView.setOnDismissAction(null);
}
}
}
}