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