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 activityUi; 35 private SearchEditTextLayout searchBox; 36 37 private boolean isActionBarSlidUp; 38 39 private final AnimationCallback fadeOutCallback = 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 ValueAnimator animator; 53 ActionBarController(ActivityUi activityUi, SearchEditTextLayout searchBox)54 public ActionBarController(ActivityUi activityUi, SearchEditTextLayout searchBox) { 55 this.activityUi = activityUi; 56 this.searchBox = searchBox; 57 } 58 59 /** @return Whether or not the action bar is currently showing (both slid down and visible) */ isActionBarShowing()60 public boolean isActionBarShowing() { 61 return !isActionBarSlidUp && !searchBox.isFadedOut(); 62 } 63 64 /** Called when the user has tapped on the collapsed search box, to start a new search query. */ onSearchBoxTapped()65 public void onSearchBoxTapped() { 66 LogUtil.d("ActionBarController.onSearchBoxTapped", "isInSearchUi " + activityUi.isInSearchUi()); 67 if (!activityUi.isInSearchUi()) { 68 searchBox.expand(true /* animate */, true /* requestFocus */); 69 } 70 } 71 72 /** Called when search UI has been exited for some reason. */ onSearchUiExited()73 public void onSearchUiExited() { 74 LogUtil.d( 75 "ActionBarController.onSearchUIExited", 76 "isExpanded: %b, isFadedOut %b", 77 searchBox.isExpanded(), 78 searchBox.isFadedOut()); 79 if (searchBox.isExpanded()) { 80 searchBox.collapse(true /* animate */); 81 } 82 if (searchBox.isFadedOut()) { 83 searchBox.fadeIn(); 84 } 85 86 slideActionBar(false /* slideUp */, false /* animate */); 87 } 88 89 /** 90 * Called to indicate that the user is trying to hide the dialpad. Should be called before any 91 * state changes have actually occurred. 92 */ onDialpadDown()93 public void onDialpadDown() { 94 LogUtil.d( 95 "ActionBarController.onDialpadDown", 96 "isInSearchUi: %b, hasSearchQuery: %b, isFadedOut: %b, isExpanded: %b", 97 activityUi.isInSearchUi(), 98 activityUi.hasSearchQuery(), 99 searchBox.isFadedOut(), 100 searchBox.isExpanded()); 101 if (activityUi.isInSearchUi()) { 102 if (searchBox.isFadedOut()) { 103 searchBox.setVisible(true); 104 } 105 if (!searchBox.isExpanded()) { 106 searchBox.expand(false /* animate */, false /* requestFocus */); 107 } 108 slideActionBar(false /* slideUp */, true /* animate */); 109 } 110 } 111 112 /** 113 * Called to indicate that the user is trying to show the dialpad. Should be called before any 114 * state changes have actually occurred. 115 */ onDialpadUp()116 public void onDialpadUp() { 117 LogUtil.d("ActionBarController.onDialpadUp", "isInSearchUi " + activityUi.isInSearchUi()); 118 if (activityUi.isInSearchUi()) { 119 slideActionBar(true /* slideUp */, true /* animate */); 120 } else { 121 // From the lists fragment 122 searchBox.fadeOut(fadeOutCallback); 123 } 124 } 125 slideActionBar(boolean slideUp, boolean animate)126 public void slideActionBar(boolean slideUp, boolean animate) { 127 LogUtil.d("ActionBarController.slidingActionBar", "up: %b, animate: %b", slideUp, animate); 128 129 if (animator != null && animator.isRunning()) { 130 animator.cancel(); 131 animator.removeAllUpdateListeners(); 132 } 133 if (animate) { 134 animator = slideUp ? ValueAnimator.ofFloat(0, 1) : ValueAnimator.ofFloat(1, 0); 135 animator.addUpdateListener( 136 animation -> { 137 final float value = (float) animation.getAnimatedValue(); 138 setHideOffset((int) (activityUi.getActionBarHeight() * value)); 139 }); 140 animator.start(); 141 } else { 142 setHideOffset(slideUp ? activityUi.getActionBarHeight() : 0); 143 } 144 isActionBarSlidUp = slideUp; 145 } 146 setAlpha(float alphaValue)147 public void setAlpha(float alphaValue) { 148 searchBox.animate().alpha(alphaValue).start(); 149 } 150 setHideOffset(int offset)151 private void setHideOffset(int offset) { 152 activityUi.setActionBarHideOffset(offset); 153 } 154 155 /** Saves the current state of the action bar into a provided {@link Bundle} */ saveInstanceState(Bundle outState)156 public void saveInstanceState(Bundle outState) { 157 outState.putBoolean(KEY_IS_SLID_UP, isActionBarSlidUp); 158 outState.putBoolean(KEY_IS_FADED_OUT, searchBox.isFadedOut()); 159 outState.putBoolean(KEY_IS_EXPANDED, searchBox.isExpanded()); 160 } 161 162 /** Restores the action bar state from a provided {@link Bundle}. */ restoreInstanceState(Bundle inState)163 public void restoreInstanceState(Bundle inState) { 164 isActionBarSlidUp = inState.getBoolean(KEY_IS_SLID_UP); 165 166 final boolean isSearchBoxFadedOut = inState.getBoolean(KEY_IS_FADED_OUT); 167 if (isSearchBoxFadedOut) { 168 if (!searchBox.isFadedOut()) { 169 searchBox.setVisible(false); 170 } 171 } else if (searchBox.isFadedOut()) { 172 searchBox.setVisible(true); 173 } 174 175 final boolean isSearchBoxExpanded = inState.getBoolean(KEY_IS_EXPANDED); 176 if (isSearchBoxExpanded) { 177 if (!searchBox.isExpanded()) { 178 searchBox.expand(false, false); 179 } 180 } else if (searchBox.isExpanded()) { 181 searchBox.collapse(false); 182 } 183 } 184 185 /** 186 * This should be called after onCreateOptionsMenu has been called, when the actionbar has been 187 * laid out and actually has a height. 188 */ restoreActionBarOffset()189 public void restoreActionBarOffset() { 190 slideActionBar(isActionBarSlidUp /* slideUp */, false /* animate */); 191 } 192 193 public interface ActivityUi { 194 isInSearchUi()195 boolean isInSearchUi(); 196 hasSearchQuery()197 boolean hasSearchQuery(); 198 getActionBarHeight()199 int getActionBarHeight(); 200 setActionBarHideOffset(int offset)201 void setActionBarHideOffset(int offset); 202 } 203 } 204