Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2013 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.dialer.widget;
     17 
     18 import com.google.common.annotations.VisibleForTesting;
     19 
     20 import android.animation.ValueAnimator;
     21 import android.animation.ValueAnimator.AnimatorUpdateListener;
     22 import android.os.Bundle;
     23 import android.util.Log;
     24 
     25 import com.android.dialer.DialtactsActivity;
     26 import com.android.phone.common.animation.AnimUtils.AnimationCallback;
     27 
     28 /**
     29  * Controls the various animated properties of the actionBar: showing/hiding, fading/revealing,
     30  * and collapsing/expanding, and assigns suitable properties to the actionBar based on the
     31  * current state of the UI.
     32  */
     33 public class ActionBarController {
     34     public static final boolean DEBUG = DialtactsActivity.DEBUG;
     35     public static final String TAG = "ActionBarController";
     36     private static final String KEY_IS_SLID_UP = "key_actionbar_is_slid_up";
     37     private static final String KEY_IS_FADED_OUT = "key_actionbar_is_faded_out";
     38     private static final String KEY_IS_EXPANDED = "key_actionbar_is_expanded";
     39 
     40     private ActivityUi mActivityUi;
     41     private SearchEditTextLayout mSearchBox;
     42 
     43     private boolean mIsActionBarSlidUp;
     44 
     45     private final AnimationCallback mFadeOutCallback = new AnimationCallback() {
     46         @Override
     47         public void onAnimationEnd() {
     48             slideActionBar(true /* slideUp */, false /* animate */);
     49         }
     50 
     51         @Override
     52         public void onAnimationCancel() {
     53             slideActionBar(true /* slideUp */, false /* animate */);
     54         }
     55     };
     56 
     57     public interface ActivityUi {
     58         public boolean isInSearchUi();
     59         public boolean hasSearchQuery();
     60         public boolean shouldShowActionBar();
     61         public int getActionBarHeight();
     62         public int getActionBarHideOffset();
     63         public void setActionBarHideOffset(int offset);
     64     }
     65 
     66     public ActionBarController(ActivityUi activityUi, SearchEditTextLayout searchBox) {
     67         mActivityUi = activityUi;
     68         mSearchBox = searchBox;
     69     }
     70 
     71     /**
     72      * @return Whether or not the action bar is currently showing (both slid down and visible)
     73      */
     74     public boolean isActionBarShowing() {
     75         return !mIsActionBarSlidUp && !mSearchBox.isFadedOut();
     76     }
     77 
     78     /**
     79      * Called when the user has tapped on the collapsed search box, to start a new search query.
     80      */
     81     public void onSearchBoxTapped() {
     82         if (DEBUG) {
     83             Log.d(TAG, "OnSearchBoxTapped: isInSearchUi " + mActivityUi.isInSearchUi());
     84         }
     85         if (!mActivityUi.isInSearchUi()) {
     86             mSearchBox.expand(true /* animate */, true /* requestFocus */);
     87         }
     88     }
     89 
     90     /**
     91      * Called when search UI has been exited for some reason.
     92      */
     93     public void onSearchUiExited() {
     94         if (DEBUG) {
     95             Log.d(TAG, "OnSearchUIExited: isExpanded " + mSearchBox.isExpanded()
     96                     + " isFadedOut: " + mSearchBox.isFadedOut()
     97                     + " shouldShowActionBar: " + mActivityUi.shouldShowActionBar());
     98         }
     99         if (mSearchBox.isExpanded()) {
    100             mSearchBox.collapse(true /* animate */);
    101         }
    102         if (mSearchBox.isFadedOut()) {
    103             mSearchBox.fadeIn();
    104         }
    105 
    106         if (mActivityUi.shouldShowActionBar()) {
    107             slideActionBar(false /* slideUp */, false /* animate */);
    108         } else {
    109             slideActionBar(true /* slideUp */, false /* animate */);
    110         }
    111     }
    112 
    113     /**
    114      * Called to indicate that the user is trying to hide the dialpad. Should be called before
    115      * any state changes have actually occurred.
    116      */
    117     public void onDialpadDown() {
    118         if (DEBUG) {
    119             Log.d(TAG, "OnDialpadDown: isInSearchUi " + mActivityUi.isInSearchUi()
    120                     + " hasSearchQuery: " + mActivityUi.hasSearchQuery()
    121                     + " isFadedOut: " + mSearchBox.isFadedOut()
    122                     + " isExpanded: " + mSearchBox.isExpanded());
    123         }
    124         if (mActivityUi.isInSearchUi()) {
    125             if (mActivityUi.hasSearchQuery()) {
    126                 if (mSearchBox.isFadedOut()) {
    127                     mSearchBox.setVisible(true);
    128                 }
    129                 if (!mSearchBox.isExpanded()) {
    130                     mSearchBox.expand(false /* animate */, false /* requestFocus */);
    131                 }
    132                 slideActionBar(false /* slideUp */, true /* animate */);
    133             } else {
    134                 mSearchBox.fadeIn();
    135             }
    136         }
    137     }
    138 
    139     /**
    140      * Called to indicate that the user is trying to show the dialpad. Should be called before
    141      * any state changes have actually occurred.
    142      */
    143     public void onDialpadUp() {
    144         if (DEBUG) {
    145             Log.d(TAG, "OnDialpadUp: isInSearchUi " + mActivityUi.isInSearchUi());
    146         }
    147         if (mActivityUi.isInSearchUi()) {
    148             slideActionBar(true /* slideUp */, true /* animate */);
    149         } else {
    150             // From the lists fragment
    151             mSearchBox.fadeOut(mFadeOutCallback);
    152         }
    153     }
    154 
    155     public void slideActionBar(boolean slideUp, boolean animate) {
    156         if (DEBUG) {
    157             Log.d(TAG, "Sliding actionBar - up: " + slideUp + " animate: " + animate);
    158         }
    159         if (animate) {
    160             ValueAnimator animator =
    161                     slideUp ? ValueAnimator.ofFloat(0, 1) : ValueAnimator.ofFloat(1, 0);
    162             animator.addUpdateListener(new AnimatorUpdateListener() {
    163                 @Override
    164                 public void onAnimationUpdate(ValueAnimator animation) {
    165                     final float value = (float) animation.getAnimatedValue();
    166                     setHideOffset(
    167                             (int) (mActivityUi.getActionBarHeight() * value));
    168                 }
    169             });
    170             animator.start();
    171         } else {
    172            setHideOffset(slideUp ? mActivityUi.getActionBarHeight() : 0);
    173         }
    174         mIsActionBarSlidUp = slideUp;
    175     }
    176 
    177     public void setAlpha(float alphaValue) {
    178         mSearchBox.animate().alpha(alphaValue).start();
    179     }
    180 
    181     public void setHideOffset(int offset) {
    182         mIsActionBarSlidUp = offset >= mActivityUi.getActionBarHeight();
    183         mActivityUi.setActionBarHideOffset(offset);
    184     }
    185 
    186     /**
    187      * @return The offset the action bar is being translated upwards by
    188      */
    189     public int getHideOffset() {
    190         return mActivityUi.getActionBarHideOffset();
    191     }
    192 
    193     public int getActionBarHeight() {
    194         return mActivityUi.getActionBarHeight();
    195     }
    196 
    197     /**
    198      * Saves the current state of the action bar into a provided {@link Bundle}
    199      */
    200     public void saveInstanceState(Bundle outState) {
    201         outState.putBoolean(KEY_IS_SLID_UP, mIsActionBarSlidUp);
    202         outState.putBoolean(KEY_IS_FADED_OUT, mSearchBox.isFadedOut());
    203         outState.putBoolean(KEY_IS_EXPANDED, mSearchBox.isExpanded());
    204     }
    205 
    206     /**
    207      * Restores the action bar state from a provided {@link Bundle}.
    208      */
    209     public void restoreInstanceState(Bundle inState) {
    210         mIsActionBarSlidUp = inState.getBoolean(KEY_IS_SLID_UP);
    211 
    212         final boolean isSearchBoxFadedOut = inState.getBoolean(KEY_IS_FADED_OUT);
    213         if (isSearchBoxFadedOut) {
    214             if (!mSearchBox.isFadedOut()) {
    215                 mSearchBox.setVisible(false);
    216             }
    217         } else if (mSearchBox.isFadedOut()) {
    218                 mSearchBox.setVisible(true);
    219         }
    220 
    221         final boolean isSearchBoxExpanded = inState.getBoolean(KEY_IS_EXPANDED);
    222         if (isSearchBoxExpanded) {
    223             if (!mSearchBox.isExpanded()) {
    224                 mSearchBox.expand(false, false);
    225             }
    226         } else if (mSearchBox.isExpanded()) {
    227                 mSearchBox.collapse(false);
    228         }
    229     }
    230 
    231     /**
    232      * This should be called after onCreateOptionsMenu has been called, when the actionbar has
    233      * been laid out and actually has a height.
    234      */
    235     public void restoreActionBarOffset() {
    236         slideActionBar(mIsActionBarSlidUp /* slideUp */, false /* animate */);
    237     }
    238 
    239     @VisibleForTesting
    240     public boolean getIsActionBarSlidUp() {
    241         return mIsActionBarSlidUp;
    242     }
    243 }
    244