598 lines
21 KiB
Java
598 lines
21 KiB
Java
/*
|
|
* Copyright (C) 2017 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License
|
|
*/
|
|
|
|
package com.android.dialer.main.impl;
|
|
|
|
import android.app.Fragment;
|
|
import android.app.FragmentTransaction;
|
|
import android.content.ActivityNotFoundException;
|
|
import android.content.Intent;
|
|
import android.os.Bundle;
|
|
import android.speech.RecognizerIntent;
|
|
import android.support.annotation.Nullable;
|
|
import android.support.annotation.VisibleForTesting;
|
|
import android.support.design.widget.FloatingActionButton;
|
|
import android.support.v7.app.AppCompatActivity;
|
|
import android.text.TextUtils;
|
|
import android.view.MenuItem;
|
|
import android.view.View;
|
|
import android.view.animation.Animation;
|
|
import android.view.animation.Animation.AnimationListener;
|
|
import android.widget.Toast;
|
|
import com.android.contacts.common.dialog.ClearFrequentsDialog;
|
|
import com.android.dialer.app.calllog.CallLogActivity;
|
|
import com.android.dialer.app.settings.DialerSettingsActivity;
|
|
import com.android.dialer.callintent.CallInitiationType;
|
|
import com.android.dialer.common.LogUtil;
|
|
import com.android.dialer.constants.ActivityRequestCodes;
|
|
import com.android.dialer.dialpadview.DialpadFragment;
|
|
import com.android.dialer.dialpadview.DialpadFragment.DialpadListener;
|
|
import com.android.dialer.dialpadview.DialpadFragment.OnDialpadQueryChangedListener;
|
|
import com.android.dialer.logging.DialerImpression;
|
|
import com.android.dialer.logging.Logger;
|
|
import com.android.dialer.logging.ScreenEvent;
|
|
import com.android.dialer.main.impl.bottomnav.BottomNavBar;
|
|
import com.android.dialer.main.impl.toolbar.MainToolbar;
|
|
import com.android.dialer.main.impl.toolbar.SearchBarListener;
|
|
import com.android.dialer.searchfragment.list.NewSearchFragment;
|
|
import com.android.dialer.searchfragment.list.NewSearchFragment.SearchFragmentListener;
|
|
import com.android.dialer.smartdial.util.SmartDialNameMatcher;
|
|
import com.android.dialer.util.TransactionSafeActivity;
|
|
import com.google.common.base.Optional;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Search controller for handling all the logic related to entering and exiting the search UI.
|
|
*
|
|
* <p>Components modified are:
|
|
*
|
|
* <ul>
|
|
* <li>Bottom Nav Bar, completely hidden when in search ui.
|
|
* <li>FAB, visible in dialpad search when dialpad is hidden. Otherwise, FAB is hidden.
|
|
* <li>Toolbar, expanded and visible when dialpad is hidden. Otherwise, hidden off screen.
|
|
* <li>Dialpad, shown through fab clicks and hidden with Android back button.
|
|
* </ul>
|
|
*
|
|
* @see #onBackPressed()
|
|
*/
|
|
public class MainSearchController implements SearchBarListener {
|
|
|
|
private static final String KEY_IS_FAB_HIDDEN = "is_fab_hidden";
|
|
private static final String KEY_TOOLBAR_SHADOW_VISIBILITY = "toolbar_shadow_visibility";
|
|
private static final String KEY_IS_TOOLBAR_EXPANDED = "is_toolbar_expanded";
|
|
private static final String KEY_IS_TOOLBAR_SLIDE_UP = "is_toolbar_slide_up";
|
|
|
|
private static final String DIALPAD_FRAGMENT_TAG = "dialpad_fragment_tag";
|
|
private static final String SEARCH_FRAGMENT_TAG = "search_fragment_tag";
|
|
|
|
private final TransactionSafeActivity activity;
|
|
private final BottomNavBar bottomNav;
|
|
private final FloatingActionButton fab;
|
|
private final MainToolbar toolbar;
|
|
private final View toolbarShadow;
|
|
|
|
/** View located underneath the toolbar that needs to animate with it. */
|
|
private final View fragmentContainer;
|
|
|
|
private final List<OnSearchShowListener> onSearchShowListenerList = new ArrayList<>();
|
|
|
|
/**
|
|
* True when an action happens that closes search (like leaving the app or placing a call). We
|
|
* want to wait until onPause is called otherwise the transition will look extremely janky.
|
|
*/
|
|
private boolean closeSearchOnPause;
|
|
|
|
private boolean callPlacedFromSearch;
|
|
private boolean requestingPermission;
|
|
|
|
private DialpadFragment dialpadFragment;
|
|
private NewSearchFragment searchFragment;
|
|
|
|
public MainSearchController(
|
|
TransactionSafeActivity activity,
|
|
BottomNavBar bottomNav,
|
|
FloatingActionButton fab,
|
|
MainToolbar toolbar,
|
|
View toolbarShadow,
|
|
View fragmentContainer) {
|
|
this.activity = activity;
|
|
this.bottomNav = bottomNav;
|
|
this.fab = fab;
|
|
this.toolbar = toolbar;
|
|
this.toolbarShadow = toolbarShadow;
|
|
this.fragmentContainer = fragmentContainer;
|
|
|
|
dialpadFragment =
|
|
(DialpadFragment) activity.getFragmentManager().findFragmentByTag(DIALPAD_FRAGMENT_TAG);
|
|
searchFragment =
|
|
(NewSearchFragment) activity.getFragmentManager().findFragmentByTag(SEARCH_FRAGMENT_TAG);
|
|
}
|
|
|
|
/** Should be called if we're showing the dialpad because of a new ACTION_DIAL intent. */
|
|
public void showDialpadFromNewIntent() {
|
|
LogUtil.enterBlock("MainSearchController.showDialpadFromNewIntent");
|
|
if (isDialpadVisible()) {
|
|
// One scenario where this can happen is if the user has the dialpad open when the receive a
|
|
// call and press add call in the in call ui which calls this method.
|
|
LogUtil.i("MainSearchController.showDialpadFromNewIntent", "Dialpad is already visible.");
|
|
|
|
// Mark started from new intent in case there is a phone number in the intent
|
|
dialpadFragment.setStartedFromNewIntent(true);
|
|
return;
|
|
}
|
|
showDialpad(/* animate=*/ false, /* fromNewIntent=*/ true);
|
|
}
|
|
|
|
/** Shows the dialpad, hides the FAB and slides the toolbar off screen. */
|
|
public void showDialpad(boolean animate) {
|
|
LogUtil.enterBlock("MainSearchController.showDialpad");
|
|
showDialpad(animate, false);
|
|
}
|
|
|
|
private void showDialpad(boolean animate, boolean fromNewIntent) {
|
|
if (isDialpadVisible()) {
|
|
LogUtil.e("MainSearchController.showDialpad", "Dialpad is already visible.");
|
|
return;
|
|
}
|
|
|
|
Logger.get(activity).logScreenView(ScreenEvent.Type.MAIN_DIALPAD, activity);
|
|
|
|
fab.hide();
|
|
toolbar.slideUp(animate, fragmentContainer);
|
|
toolbar.expand(animate, Optional.absent(), /* requestFocus */ false);
|
|
toolbarShadow.setVisibility(View.VISIBLE);
|
|
|
|
activity.setTitle(R.string.dialpad_activity_title);
|
|
|
|
FragmentTransaction transaction = activity.getFragmentManager().beginTransaction();
|
|
|
|
// Show Search
|
|
if (searchFragment == null) {
|
|
searchFragment = NewSearchFragment.newInstance();
|
|
transaction.add(R.id.search_fragment_container, searchFragment, SEARCH_FRAGMENT_TAG);
|
|
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
|
|
} else if (!isSearchVisible()) {
|
|
transaction.show(searchFragment);
|
|
}
|
|
|
|
// Show Dialpad
|
|
if (dialpadFragment == null) {
|
|
dialpadFragment = new DialpadFragment();
|
|
dialpadFragment.setStartedFromNewIntent(fromNewIntent);
|
|
transaction.add(R.id.dialpad_fragment_container, dialpadFragment, DIALPAD_FRAGMENT_TAG);
|
|
searchFragment.setQuery("", CallInitiationType.Type.DIALPAD);
|
|
} else {
|
|
dialpadFragment.setStartedFromNewIntent(fromNewIntent);
|
|
transaction.show(dialpadFragment);
|
|
}
|
|
transaction.commit();
|
|
|
|
notifyListenersOnSearchOpen();
|
|
}
|
|
|
|
/**
|
|
* Hides the dialpad, reveals the FAB and slides the toolbar back onto the screen.
|
|
*
|
|
* <p>This method intentionally "hides" and does not "remove" the dialpad in order to preserve its
|
|
* state (i.e. we call {@link FragmentTransaction#hide(Fragment)} instead of {@link
|
|
* FragmentTransaction#remove(Fragment)}.
|
|
*
|
|
* @see {@link #closeSearch(boolean)} to "remove" the dialpad.
|
|
*/
|
|
private void hideDialpad(boolean animate) {
|
|
LogUtil.enterBlock("MainSearchController.hideDialpad");
|
|
if (dialpadFragment == null) {
|
|
LogUtil.e("MainSearchController.hideDialpad", "Dialpad fragment is null.");
|
|
return;
|
|
}
|
|
|
|
if (!dialpadFragment.isAdded()) {
|
|
LogUtil.e("MainSearchController.hideDialpad", "Dialpad fragment is not added.");
|
|
return;
|
|
}
|
|
|
|
if (dialpadFragment.isHidden()) {
|
|
LogUtil.e("MainSearchController.hideDialpad", "Dialpad fragment is already hidden.");
|
|
return;
|
|
}
|
|
|
|
if (!dialpadFragment.isDialpadSlideUp()) {
|
|
LogUtil.e("MainSearchController.hideDialpad", "Dialpad fragment is already slide down.");
|
|
return;
|
|
}
|
|
|
|
fab.show();
|
|
toolbar.slideDown(animate, fragmentContainer);
|
|
toolbar.transferQueryFromDialpad(dialpadFragment.getQuery());
|
|
activity.setTitle(R.string.main_activity_label);
|
|
|
|
dialpadFragment.setAnimate(animate);
|
|
dialpadFragment.slideDown(
|
|
animate,
|
|
new AnimationListener() {
|
|
@Override
|
|
public void onAnimationStart(Animation animation) {}
|
|
|
|
@Override
|
|
public void onAnimationEnd(Animation animation) {
|
|
if (activity.isSafeToCommitTransactions()
|
|
&& !(activity.isFinishing() || activity.isDestroyed())) {
|
|
activity.getFragmentManager().beginTransaction().hide(dialpadFragment).commit();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onAnimationRepeat(Animation animation) {}
|
|
});
|
|
}
|
|
|
|
private void hideBottomNav() {
|
|
bottomNav.setVisibility(View.GONE);
|
|
}
|
|
|
|
private void showBottomNav() {
|
|
bottomNav.setVisibility(View.VISIBLE);
|
|
}
|
|
|
|
/** Should be called when {@link DialpadListener#onDialpadShown()} is called. */
|
|
public void onDialpadShown() {
|
|
LogUtil.enterBlock("MainSearchController.onDialpadShown");
|
|
dialpadFragment.slideUp(true);
|
|
hideBottomNav();
|
|
}
|
|
|
|
/**
|
|
* @see SearchFragmentListener#onSearchListTouch()
|
|
* <p>There are 4 scenarios we support to provide a nice UX experience:
|
|
* <ol>
|
|
* <li>When the dialpad is visible with an empty query, close the search UI.
|
|
* <li>When the dialpad is visible with a non-empty query, hide the dialpad.
|
|
* <li>When the regular search UI is visible with an empty query, close the search UI.
|
|
* <li>When the regular search UI is visible with a non-empty query, hide the keyboard.
|
|
* </ol>
|
|
*/
|
|
public void onSearchListTouch() {
|
|
LogUtil.enterBlock("MainSearchController.onSearchListTouched");
|
|
if (isDialpadVisible()) {
|
|
if (TextUtils.isEmpty(dialpadFragment.getQuery())) {
|
|
Logger.get(activity)
|
|
.logImpression(
|
|
DialerImpression.Type.MAIN_TOUCH_DIALPAD_SEARCH_LIST_TO_CLOSE_SEARCH_AND_DIALPAD);
|
|
closeSearch(true);
|
|
} else {
|
|
Logger.get(activity)
|
|
.logImpression(DialerImpression.Type.MAIN_TOUCH_DIALPAD_SEARCH_LIST_TO_HIDE_DIALPAD);
|
|
hideDialpad(/* animate=*/ true);
|
|
}
|
|
} else if (isSearchVisible()) {
|
|
if (TextUtils.isEmpty(toolbar.getQuery())) {
|
|
Logger.get(activity)
|
|
.logImpression(DialerImpression.Type.MAIN_TOUCH_SEARCH_LIST_TO_CLOSE_SEARCH);
|
|
closeSearch(true);
|
|
} else {
|
|
Logger.get(activity)
|
|
.logImpression(DialerImpression.Type.MAIN_TOUCH_SEARCH_LIST_TO_HIDE_KEYBOARD);
|
|
closeKeyboard();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Should be called when the user presses the back button.
|
|
*
|
|
* @return true if #onBackPressed() handled to action.
|
|
*/
|
|
public boolean onBackPressed() {
|
|
if (isDialpadVisible() && !TextUtils.isEmpty(dialpadFragment.getQuery())) {
|
|
LogUtil.i("MainSearchController.onBackPressed", "Dialpad visible with query");
|
|
Logger.get(activity)
|
|
.logImpression(DialerImpression.Type.MAIN_PRESS_BACK_BUTTON_TO_HIDE_DIALPAD);
|
|
hideDialpad(/* animate=*/ true);
|
|
return true;
|
|
} else if (isSearchVisible()) {
|
|
LogUtil.i("MainSearchController.onBackPressed", "Search is visible");
|
|
Logger.get(activity)
|
|
.logImpression(
|
|
isDialpadVisible()
|
|
? DialerImpression.Type.MAIN_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH_AND_DIALPAD
|
|
: DialerImpression.Type.MAIN_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH);
|
|
closeSearch(true);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/** Calls {@link #hideDialpad(boolean)}, removes the search fragment and clears the dialpad. */
|
|
private void closeSearch(boolean animate) {
|
|
LogUtil.enterBlock("MainSearchController.closeSearch");
|
|
if (searchFragment == null) {
|
|
LogUtil.e("MainSearchController.closeSearch", "Search fragment is null.");
|
|
return;
|
|
}
|
|
|
|
if (!searchFragment.isAdded()) {
|
|
LogUtil.e("MainSearchController.closeSearch", "Search fragment isn't added.");
|
|
return;
|
|
}
|
|
|
|
if (searchFragment.isHidden()) {
|
|
LogUtil.e("MainSearchController.closeSearch", "Search fragment is already hidden.");
|
|
return;
|
|
}
|
|
|
|
if (isDialpadVisible()) {
|
|
hideDialpad(animate);
|
|
} else if (!fab.isShown()) {
|
|
fab.show();
|
|
}
|
|
showBottomNav();
|
|
toolbar.collapse(animate);
|
|
toolbarShadow.setVisibility(View.GONE);
|
|
activity.getFragmentManager().beginTransaction().hide(searchFragment).commit();
|
|
|
|
// Clear the dialpad so the phone number isn't persisted between search sessions.
|
|
if (dialpadFragment != null) {
|
|
// Temporarily disable accessibility when we clear the dialpad, since it should be
|
|
// invisible and should not announce anything.
|
|
dialpadFragment
|
|
.getDigitsWidget()
|
|
.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
|
|
dialpadFragment.clearDialpad();
|
|
dialpadFragment
|
|
.getDigitsWidget()
|
|
.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
|
|
}
|
|
|
|
notifyListenersOnSearchClose();
|
|
}
|
|
|
|
@Nullable
|
|
protected DialpadFragment getDialpadFragment() {
|
|
return dialpadFragment;
|
|
}
|
|
|
|
private boolean isDialpadVisible() {
|
|
return dialpadFragment != null
|
|
&& dialpadFragment.isAdded()
|
|
&& !dialpadFragment.isHidden()
|
|
&& dialpadFragment.isDialpadSlideUp();
|
|
}
|
|
|
|
private boolean isSearchVisible() {
|
|
return searchFragment != null && searchFragment.isAdded() && !searchFragment.isHidden();
|
|
}
|
|
|
|
/** Returns true if the search UI is visible. */
|
|
public boolean isInSearch() {
|
|
return isSearchVisible();
|
|
}
|
|
|
|
/** Closes the keyboard if necessary. */
|
|
private void closeKeyboard() {
|
|
if (searchFragment != null && searchFragment.isAdded()) {
|
|
toolbar.hideKeyboard();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Opens search in regular/search bar search mode.
|
|
*
|
|
* <p>Hides fab, expands toolbar and starts the search fragment.
|
|
*/
|
|
@Override
|
|
public void onSearchBarClicked() {
|
|
LogUtil.enterBlock("MainSearchController.onSearchBarClicked");
|
|
Logger.get(activity).logImpression(DialerImpression.Type.MAIN_CLICK_SEARCH_BAR);
|
|
openSearch(Optional.absent());
|
|
}
|
|
|
|
private void openSearch(Optional<String> query) {
|
|
LogUtil.enterBlock("MainSearchController.openSearch");
|
|
|
|
Logger.get(activity).logScreenView(ScreenEvent.Type.MAIN_SEARCH, activity);
|
|
|
|
fab.hide();
|
|
toolbar.expand(/* animate=*/ true, query, /* requestFocus */ true);
|
|
toolbar.showKeyboard();
|
|
toolbarShadow.setVisibility(View.VISIBLE);
|
|
hideBottomNav();
|
|
|
|
FragmentTransaction transaction = activity.getFragmentManager().beginTransaction();
|
|
// Show Search
|
|
if (searchFragment == null) {
|
|
searchFragment = NewSearchFragment.newInstance();
|
|
transaction.add(R.id.search_fragment_container, searchFragment, SEARCH_FRAGMENT_TAG);
|
|
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
|
|
} else if (!isSearchVisible()) {
|
|
transaction.show(searchFragment);
|
|
}
|
|
|
|
searchFragment.setQuery(
|
|
query.isPresent() ? query.get() : "", CallInitiationType.Type.REGULAR_SEARCH);
|
|
|
|
if (activity.isSafeToCommitTransactions()) {
|
|
transaction.commit();
|
|
}
|
|
|
|
notifyListenersOnSearchOpen();
|
|
}
|
|
|
|
@Override
|
|
public void onSearchBackButtonClicked() {
|
|
LogUtil.enterBlock("MainSearchController.onSearchBackButtonClicked");
|
|
closeSearch(true);
|
|
}
|
|
|
|
@Override
|
|
public void onSearchQueryUpdated(String query) {
|
|
if (searchFragment != null) {
|
|
searchFragment.setQuery(query, CallInitiationType.Type.REGULAR_SEARCH);
|
|
}
|
|
}
|
|
|
|
/** @see OnDialpadQueryChangedListener#onDialpadQueryChanged(java.lang.String) */
|
|
public void onDialpadQueryChanged(String query) {
|
|
String normalizedQuery = SmartDialNameMatcher.normalizeNumber(/* context = */ activity, query);
|
|
if (searchFragment != null) {
|
|
searchFragment.setRawNumber(query);
|
|
searchFragment.setQuery(normalizedQuery, CallInitiationType.Type.DIALPAD);
|
|
}
|
|
dialpadFragment.process_quote_emergency_unquote(normalizedQuery);
|
|
}
|
|
|
|
@Override
|
|
public void onVoiceButtonClicked(VoiceSearchResultCallback voiceSearchResultCallback) {
|
|
Logger.get(activity).logImpression(DialerImpression.Type.MAIN_CLICK_SEARCH_BAR_VOICE_BUTTON);
|
|
try {
|
|
Intent voiceIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
|
|
activity.startActivityForResult(voiceIntent, ActivityRequestCodes.DIALTACTS_VOICE_SEARCH);
|
|
} catch (ActivityNotFoundException e) {
|
|
Toast.makeText(activity, R.string.voice_search_not_available, Toast.LENGTH_SHORT).show();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onMenuItemClicked(MenuItem menuItem) {
|
|
if (menuItem.getItemId() == R.id.settings) {
|
|
activity.startActivity(new Intent(activity, DialerSettingsActivity.class));
|
|
Logger.get(activity).logScreenView(ScreenEvent.Type.SETTINGS, activity);
|
|
return true;
|
|
} else if (menuItem.getItemId() == R.id.clear_frequents) {
|
|
ClearFrequentsDialog.show(activity.getFragmentManager());
|
|
Logger.get(activity).logScreenView(ScreenEvent.Type.CLEAR_FREQUENTS, activity);
|
|
return true;
|
|
} else if (menuItem.getItemId() == R.id.menu_call_history) {
|
|
final Intent intent = new Intent(activity, CallLogActivity.class);
|
|
activity.startActivity(intent);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void onActivityPause() {
|
|
LogUtil.enterBlock("MainSearchController.onActivityPause");
|
|
closeKeyboard();
|
|
|
|
if (closeSearchOnPause) {
|
|
if (isInSearch() && (callPlacedFromSearch || !isDialpadVisible())) {
|
|
closeSearch(false);
|
|
}
|
|
closeSearchOnPause = false;
|
|
callPlacedFromSearch = false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onUserLeaveHint() {
|
|
if (isInSearch()) {
|
|
// Requesting a permission causes this to be called and we want search to remain open when
|
|
// that happens. Otherwise, close search.
|
|
closeSearchOnPause = !requestingPermission;
|
|
|
|
// Always hide the keyboard when the user leaves dialer (including permission requests)
|
|
closeKeyboard();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onCallPlacedFromSearch() {
|
|
closeSearchOnPause = true;
|
|
callPlacedFromSearch = true;
|
|
}
|
|
|
|
@Override
|
|
public void requestingPermission() {
|
|
LogUtil.enterBlock("MainSearchController.requestingPermission");
|
|
requestingPermission = true;
|
|
}
|
|
|
|
public void onVoiceResults(int resultCode, Intent data) {
|
|
if (resultCode == AppCompatActivity.RESULT_OK) {
|
|
ArrayList<String> matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
|
|
if (matches.size() > 0) {
|
|
LogUtil.i("MainSearchController.onVoiceResults", "voice search - match found");
|
|
openSearch(Optional.of(matches.get(0)));
|
|
} else {
|
|
LogUtil.i("MainSearchController.onVoiceResults", "voice search - nothing heard");
|
|
}
|
|
} else {
|
|
LogUtil.e("MainSearchController.onVoiceResults", "voice search failed");
|
|
}
|
|
}
|
|
|
|
public void onSaveInstanceState(Bundle bundle) {
|
|
bundle.putBoolean(KEY_IS_FAB_HIDDEN, !fab.isShown());
|
|
bundle.putInt(KEY_TOOLBAR_SHADOW_VISIBILITY, toolbarShadow.getVisibility());
|
|
bundle.putBoolean(KEY_IS_TOOLBAR_EXPANDED, toolbar.isExpanded());
|
|
bundle.putBoolean(KEY_IS_TOOLBAR_SLIDE_UP, toolbar.isSlideUp());
|
|
}
|
|
|
|
public void onRestoreInstanceState(Bundle savedInstanceState) {
|
|
toolbarShadow.setVisibility(savedInstanceState.getInt(KEY_TOOLBAR_SHADOW_VISIBILITY));
|
|
if (savedInstanceState.getBoolean(KEY_IS_FAB_HIDDEN, false)) {
|
|
fab.hide();
|
|
}
|
|
boolean isSlideUp = savedInstanceState.getBoolean(KEY_IS_TOOLBAR_SLIDE_UP, false);
|
|
if (isSlideUp) {
|
|
toolbar.slideUp(false, fragmentContainer);
|
|
}
|
|
if (savedInstanceState.getBoolean(KEY_IS_TOOLBAR_EXPANDED, false)) {
|
|
// If the toolbar is slide up, that means the dialpad is showing. Thus we don't want to
|
|
// request focus or we'll break physical/bluetooth keyboards typing.
|
|
toolbar.expand(/* animate */ false, Optional.absent(), /* requestFocus */ !isSlideUp);
|
|
}
|
|
}
|
|
|
|
public void addOnSearchShowListener(OnSearchShowListener listener) {
|
|
onSearchShowListenerList.add(listener);
|
|
}
|
|
|
|
public void removeOnSearchShowListener(OnSearchShowListener listener) {
|
|
onSearchShowListenerList.remove(listener);
|
|
}
|
|
|
|
private void notifyListenersOnSearchOpen() {
|
|
for (OnSearchShowListener listener : onSearchShowListenerList) {
|
|
listener.onSearchOpen();
|
|
}
|
|
}
|
|
|
|
private void notifyListenersOnSearchClose() {
|
|
for (OnSearchShowListener listener : onSearchShowListenerList) {
|
|
listener.onSearchClose();
|
|
}
|
|
}
|
|
|
|
/** Listener for search fragment show states change */
|
|
public interface OnSearchShowListener {
|
|
void onSearchOpen();
|
|
|
|
void onSearchClose();
|
|
}
|
|
|
|
@VisibleForTesting
|
|
void setDialpadFragment(DialpadFragment dialpadFragment) {
|
|
this.dialpadFragment = dialpadFragment;
|
|
}
|
|
|
|
@VisibleForTesting
|
|
void setSearchFragment(NewSearchFragment searchFragment) {
|
|
this.searchFragment = searchFragment;
|
|
}
|
|
}
|