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