Home | History | Annotate | Download | only in keyguard
      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.os.Handler;
     19 import android.os.Looper;
     20 import android.util.Log;
     21 import android.view.View;
     22 
     23 public 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) {
    143                 scl.fadeOutChallenge();
    144             }
    145             final int currentFlags = mKeyguardWidgetPager.getSystemUiVisibility();
    146             final int newFlags = isCameraPage ? (currentFlags | View.STATUS_BAR_DISABLE_SEARCH)
    147                     : (currentFlags & ~View.STATUS_BAR_DISABLE_SEARCH);
    148             mKeyguardWidgetPager.setSystemUiVisibility(newFlags);
    149         }
    150 
    151         // If the page we're settling to is the same as we started on, and the action of
    152         // moving the page hid the security, we restore it immediately.
    153         if (mPageIndexOnPageBeginMoving == mKeyguardWidgetPager.getNextPage() &&
    154                 mChallengeLayout instanceof SlidingChallengeLayout) {
    155             SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
    156             scl.fadeInChallenge();
    157             mKeyguardWidgetPager.setWidgetToResetOnPageFadeOut(-1);
    158         }
    159         mPageIndexOnPageBeginMoving = -1;
    160     }
    161 
    162     public void onPageSwitched(View newPage, int newPageIndex) {
    163         // Reset the previous page size and ensure the current page is sized appropriately.
    164         // We only modify the page state if it is not currently under control by the slider.
    165         // This prevents conflicts.
    166 
    167         // If the page hasn't switched, don't bother with any of this
    168         if (mCurrentPage == newPageIndex) return;
    169 
    170         if (mKeyguardWidgetPager != null && mChallengeLayout != null) {
    171             KeyguardWidgetFrame prevPage = mKeyguardWidgetPager.getWidgetPageAt(mCurrentPage);
    172             if (prevPage != null && mCurrentPage != mPageListeningToSlider && mCurrentPage
    173                     != mKeyguardWidgetPager.getWidgetToResetOnPageFadeOut()) {
    174                 prevPage.resetSize();
    175             }
    176 
    177             KeyguardWidgetFrame newCurPage = mKeyguardWidgetPager.getWidgetPageAt(newPageIndex);
    178             boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping();
    179             if (challengeOverlapping && !newCurPage.isSmall()
    180                     && mPageListeningToSlider != newPageIndex) {
    181                 newCurPage.shrinkWidget();
    182             }
    183         }
    184 
    185         mCurrentPage = newPageIndex;
    186     }
    187 
    188     public void onPageBeginWarp() {
    189         fadeOutSecurity(SlidingChallengeLayout.CHALLENGE_FADE_OUT_DURATION);
    190         View frame = mKeyguardWidgetPager.getPageAt(mKeyguardWidgetPager.getPageWarpIndex());
    191         ((KeyguardWidgetFrame)frame).showFrame(this);
    192     }
    193 
    194     public void onPageEndWarp() {
    195         fadeInSecurity(SlidingChallengeLayout.CHALLENGE_FADE_IN_DURATION);
    196         View frame = mKeyguardWidgetPager.getPageAt(mKeyguardWidgetPager.getPageWarpIndex());
    197         ((KeyguardWidgetFrame)frame).hideFrame(this);
    198     }
    199 
    200     private int getChallengeTopRelativeToFrame(KeyguardWidgetFrame frame, int top) {
    201         mTmpPoint[0] = 0;
    202         mTmpPoint[1] = top;
    203         mapPoint((View) mChallengeLayout, frame, mTmpPoint);
    204         return mTmpPoint[1];
    205     }
    206 
    207     /**
    208      * Simple method to map a point from one view's coordinates to another's. Note: this method
    209      * doesn't account for transforms, so if the views will be transformed, this should not be used.
    210      *
    211      * @param fromView The view to which the point is relative
    212      * @param toView The view into which the point should be mapped
    213      * @param pt The point
    214      */
    215     private void mapPoint(View fromView, View toView, int pt[]) {
    216         fromView.getLocationInWindow(mTmpLoc);
    217 
    218         int x = mTmpLoc[0];
    219         int y = mTmpLoc[1];
    220 
    221         toView.getLocationInWindow(mTmpLoc);
    222         int vX = mTmpLoc[0];
    223         int vY = mTmpLoc[1];
    224 
    225         pt[0] += x - vX;
    226         pt[1] += y - vY;
    227     }
    228 
    229     private void userActivity() {
    230         if (mKeyguardHostView != null) {
    231             mKeyguardHostView.onUserActivityTimeoutChanged();
    232             mKeyguardHostView.userActivity();
    233         }
    234     }
    235 
    236     @Override
    237     public void onScrollStateChanged(int scrollState) {
    238         if (mKeyguardWidgetPager == null || mChallengeLayout == null) return;
    239 
    240         boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping();
    241 
    242         if (scrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
    243             KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
    244             if (frame == null) return;
    245 
    246             if (!challengeOverlapping) {
    247                 if (!mKeyguardWidgetPager.isPageMoving()) {
    248                     frame.resetSize();
    249                     userActivity();
    250                 } else {
    251                     mKeyguardWidgetPager.setWidgetToResetOnPageFadeOut(mPageListeningToSlider);
    252                 }
    253             }
    254             if (frame.isSmall()) {
    255                 // This is to make sure that if the scroller animation gets cut off midway
    256                 // that the frame doesn't stay in a partial down position.
    257                 frame.setFrameHeight(frame.getSmallFrameHeight());
    258             }
    259             if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
    260                 frame.hideFrame(this);
    261             }
    262             updateEdgeSwiping();
    263 
    264             if (mChallengeLayout.isChallengeShowing()) {
    265                 mKeyguardSecurityContainer.onResume(KeyguardSecurityView.VIEW_REVEALED);
    266             } else {
    267                 mKeyguardSecurityContainer.onPause();
    268             }
    269             mPageListeningToSlider = -1;
    270         } else if (mLastScrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
    271             // Whether dragging or settling, if the last state was idle, we use this signal
    272             // to update the current page who will receive events from the sliding challenge.
    273             // We resize the frame as appropriate.
    274             mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
    275             KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
    276             if (frame == null) return;
    277 
    278             // Skip showing the frame and shrinking the widget if we are
    279             if (!mChallengeLayout.isBouncing()) {
    280                 if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
    281                     frame.showFrame(this);
    282                 }
    283 
    284                 // As soon as the security begins sliding, the widget becomes small (if it wasn't
    285                 // small to begin with).
    286                 if (!frame.isSmall()) {
    287                     // We need to fetch the final page, in case the pages are in motion.
    288                     mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
    289                     frame.shrinkWidget(false);
    290                 }
    291             } else {
    292                 if (!frame.isSmall()) {
    293                     // We need to fetch the final page, in case the pages are in motion.
    294                     mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
    295                 }
    296             }
    297 
    298             // View is on the move.  Pause the security view until it completes.
    299             mKeyguardSecurityContainer.onPause();
    300         }
    301         mLastScrollState = scrollState;
    302     }
    303 
    304     @Override
    305     public void onScrollPositionChanged(float scrollPosition, int challengeTop) {
    306         mChallengeTop = challengeTop;
    307         KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
    308         if (frame != null && mLastScrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
    309             frame.adjustFrame(getChallengeTopRelativeToFrame(frame, mChallengeTop));
    310         }
    311     }
    312 
    313     private Runnable mHideHintsRunnable = new Runnable() {
    314         @Override
    315         public void run() {
    316             if (mKeyguardWidgetPager != null) {
    317                 mKeyguardWidgetPager.hideOutlinesAndSidePages();
    318             }
    319         }
    320     };
    321 
    322     public void showUsabilityHints() {
    323         mMainQueue.postDelayed( new Runnable() {
    324             @Override
    325             public void run() {
    326                 mKeyguardSecurityContainer.showUsabilityHint();
    327             }
    328         } , SCREEN_ON_RING_HINT_DELAY);
    329         if (SHOW_INITIAL_PAGE_HINTS) {
    330             mKeyguardWidgetPager.showInitialPageHints();
    331         }
    332         if (mHideHintsRunnable != null) {
    333             mMainQueue.postDelayed(mHideHintsRunnable, SCREEN_ON_HINT_DURATION);
    334         }
    335     }
    336 
    337     // ChallengeLayout.OnBouncerStateChangedListener
    338     @Override
    339     public void onBouncerStateChanged(boolean bouncerActive) {
    340         if (bouncerActive) {
    341             mKeyguardWidgetPager.zoomOutToBouncer();
    342         } else {
    343             mKeyguardWidgetPager.zoomInFromBouncer();
    344             if (mKeyguardHostView != null) {
    345                 mKeyguardHostView.setOnDismissAction(null);
    346             }
    347         }
    348     }
    349 }
    350