summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--java/com/android/dialer/app/DialtactsActivity.java4
-rw-r--r--java/com/android/dialer/dialpadview/DialpadFragment.java10
-rw-r--r--java/com/android/dialer/main/impl/MainActivity.java180
-rw-r--r--java/com/android/dialer/main/impl/res/layout/main_activity.xml9
-rw-r--r--java/com/android/dialer/main/impl/toolbar/MainToolbar.java25
-rw-r--r--java/com/android/dialer/main/impl/toolbar/SearchBarListener.java3
-rw-r--r--java/com/android/dialer/main/impl/toolbar/SearchBarView.java8
-rw-r--r--java/com/android/dialer/searchfragment/list/NewSearchFragment.java12
8 files changed, 193 insertions, 58 deletions
diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java
index 65965f44e..7592c6669 100644
--- a/java/com/android/dialer/app/DialtactsActivity.java
+++ b/java/com/android/dialer/app/DialtactsActivity.java
@@ -1450,18 +1450,16 @@ public class DialtactsActivity extends TransactionSafeActivity
}
@Override
- public boolean onSearchListTouch(MotionEvent event) {
+ public void onSearchListTouch() {
if (isDialpadShown) {
PerformanceReport.recordClick(UiAction.Type.CLOSE_DIALPAD);
hideDialpadFragment(true, false);
if (TextUtils.isEmpty(dialpadQuery)) {
exitSearchUi();
}
- return true;
} else {
UiUtil.hideKeyboardFrom(this, searchEditTextLayout);
}
- return false;
}
@Override
diff --git a/java/com/android/dialer/dialpadview/DialpadFragment.java b/java/com/android/dialer/dialpadview/DialpadFragment.java
index 07e401cab..2796fca77 100644
--- a/java/com/android/dialer/dialpadview/DialpadFragment.java
+++ b/java/com/android/dialer/dialpadview/DialpadFragment.java
@@ -59,6 +59,7 @@ import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
@@ -140,6 +141,7 @@ public class DialpadFragment extends Fragment
private static final String EXTRA_SEND_EMPTY_FLASH = "com.android.phone.extra.SEND_EMPTY_FLASH";
private static final String PREF_DIGITS_FILLED_BY_INTENT = "pref_digits_filled_by_intent";
+ private static final String PREF_IS_DIALPAD_SLIDE_OUT = "pref_is_dialpad_slide_out";
private static Optional<String> currentCountryIsoForTesting = Optional.absent();
@@ -346,6 +348,7 @@ public class DialpadFragment extends Fragment
if (state != null) {
digitsFilledByIntent = state.getBoolean(PREF_DIGITS_FILLED_BY_INTENT);
+ isDialpadSlideUp = state.getBoolean(PREF_IS_DIALPAD_SLIDE_OUT);
}
dialpadSlideInDuration = getResources().getInteger(R.integer.dialpad_slide_in_duration);
@@ -412,7 +415,7 @@ public class DialpadFragment extends Fragment
.setOnTouchListener(
(v, event) -> {
if (isDigitsEmpty()) {
- if (getActivity() != null) {
+ if (getActivity() != null && event.getAction() == MotionEvent.ACTION_UP) {
LogUtil.i("DialpadFragment.onCreateView", "dialpad spacer touched");
return ((HostInterface) getActivity()).onDialpadSpacerTouchWithEmptyQuery();
}
@@ -777,6 +780,7 @@ public class DialpadFragment extends Fragment
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(PREF_DIGITS_FILLED_BY_INTENT, digitsFilledByIntent);
+ outState.putBoolean(PREF_IS_DIALPAD_SLIDE_OUT, isDialpadSlideUp);
}
@Override
@@ -1559,6 +1563,10 @@ public class DialpadFragment extends Fragment
getView().startAnimation(slideUp);
}
+ public boolean isDialpadSlideUp() {
+ return isDialpadSlideUp;
+ }
+
/** Returns the text in the dialpad */
public String getQuery() {
return digits.getText().toString();
diff --git a/java/com/android/dialer/main/impl/MainActivity.java b/java/com/android/dialer/main/impl/MainActivity.java
index 8bdb295c7..8aac9e810 100644
--- a/java/com/android/dialer/main/impl/MainActivity.java
+++ b/java/com/android/dialer/main/impl/MainActivity.java
@@ -25,6 +25,7 @@ import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
+import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.widget.ImageView;
@@ -42,14 +43,24 @@ import com.android.dialer.main.impl.BottomNavBar.OnBottomNavTabSelectedListener;
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.speeddial.SpeedDialFragment;
+import com.android.dialer.util.ViewUtil;
import com.android.dialer.voicemail.listui.NewVoicemailFragment;
+import com.google.common.base.Optional;
/** This is the main activity for dialer. It hosts favorites, call log, search, dialpad, etc... */
public final class MainActivity extends AppCompatActivity
- implements OnContactSelectedListener, OnDialpadQueryChangedListener, DialpadListener {
+ implements OnContactSelectedListener,
+ OnDialpadQueryChangedListener,
+ DialpadListener,
+ DialpadFragment.HostInterface,
+ SearchFragmentListener {
+
+ private static final String IS_FAB_HIDDEN_KEY = "is_fab_hidden";
private SearchController searchController;
+ private FloatingActionButton fab;
/**
* @param context Context of the application package implementing MainActivity class.
@@ -70,18 +81,33 @@ public final class MainActivity extends AppCompatActivity
}
private void initLayout() {
- FloatingActionButton fab = findViewById(R.id.fab);
+ fab = findViewById(R.id.fab);
fab.setOnClickListener(v -> searchController.showDialpad(true));
MainToolbar toolbar = findViewById(R.id.toolbar);
- toolbar.setSearchBarListener(new MainSearchBarListener());
- searchController = new SearchController(fab, toolbar);
setSupportActionBar(findViewById(R.id.toolbar));
BottomNavBar navBar = findViewById(R.id.bottom_nav_bar);
navBar.setOnTabSelectedListener(new MainBottomNavBarBottomNavTabListener());
// TODO(calderwoodra): Implement last tab
navBar.selectTab(BottomNavBar.TabIndex.SPEED_DIAL);
+
+ searchController = new SearchController(navBar, fab, toolbar);
+ toolbar.setSearchBarListener(searchController);
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle bundle) {
+ super.onSaveInstanceState(bundle);
+ bundle.putBoolean(IS_FAB_HIDDEN_KEY, !fab.isShown());
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ if (savedInstanceState.getBoolean(IS_FAB_HIDDEN_KEY, false)) {
+ fab.hide();
+ }
}
@Override
@@ -119,31 +145,59 @@ public final class MainActivity extends AppCompatActivity
super.onBackPressed();
}
- /** Search controller for handling all the logic related to hiding/showing search and dialpad. */
- private final class SearchController {
+ @Override // DialpadFragment.HostInterface
+ public boolean onDialpadSpacerTouchWithEmptyQuery() {
+ searchController.onBackPressed();
+ return true;
+ }
+
+ @Override // SearchFragmentListener
+ public void onSearchListTouch() {
+ searchController.onBackPressed();
+ }
+
+ @Override // SearchFragmentListener
+ public void onCallPlacedFromSearch() {
+ // TODO(calderwoodra): logging
+ }
+
+ /**
+ * 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()
+ */
+ private final class SearchController implements SearchBarListener {
private static final String DIALPAD_FRAGMENT_TAG = "dialpad_fragment_tag";
private static final String SEARCH_FRAGMENT_TAG = "search_fragment_tag";
+ private final BottomNavBar bottomNav;
private final FloatingActionButton fab;
private final MainToolbar toolbar;
- private boolean isDialpadVisible;
- private boolean isSearchVisible;
-
- private SearchController(FloatingActionButton fab, MainToolbar toolbar) {
+ private SearchController(
+ BottomNavBar bottomNav, FloatingActionButton fab, MainToolbar toolbar) {
+ this.bottomNav = bottomNav;
this.fab = fab;
this.toolbar = toolbar;
}
/** Shows the dialpad, hides the FAB and slides the toolbar off screen. */
public void showDialpad(boolean animate) {
- Assert.checkArgument(!isDialpadVisible);
- isDialpadVisible = true;
- isSearchVisible = true;
+ Assert.checkArgument(!isDialpadVisible());
fab.hide();
toolbar.slideUp(animate);
+ toolbar.expand(animate, Optional.absent());
setTitle(R.string.dialpad_activity_title);
android.app.FragmentTransaction transaction = getFragmentManager().beginTransaction();
@@ -152,14 +206,14 @@ public final class MainActivity extends AppCompatActivity
if (getSearchFragment() == null) {
NewSearchFragment searchFragment = NewSearchFragment.newInstance(false);
transaction.add(R.id.search_fragment_container, searchFragment, SEARCH_FRAGMENT_TAG);
- } else if (!isSearchVisible) {
+ } else if (!isSearchVisible()) {
transaction.show(getSearchFragment());
}
// Show Dialpad
if (getDialpadFragment() == null) {
DialpadFragment dialpadFragment = new DialpadFragment();
- transaction.add(R.id.search_fragment_container, dialpadFragment, DIALPAD_FRAGMENT_TAG);
+ transaction.add(R.id.dialpad_fragment_container, dialpadFragment, DIALPAD_FRAGMENT_TAG);
} else {
DialpadFragment dialpadFragment = getDialpadFragment();
transaction.show(dialpadFragment);
@@ -168,9 +222,8 @@ public final class MainActivity extends AppCompatActivity
}
/** Hides the dialpad, reveals the FAB and slides the toolbar back onto the screen. */
- public void hideDialpad(boolean animate) {
- Assert.checkArgument(isDialpadVisible);
- isDialpadVisible = false;
+ public void hideDialpad(boolean animate, boolean bottomNavVisible) {
+ Assert.checkArgument(isDialpadVisible());
fab.show();
toolbar.slideDown(animate);
@@ -182,7 +235,15 @@ public final class MainActivity extends AppCompatActivity
animate,
new AnimationListener() {
@Override
- public void onAnimationStart(Animation animation) {}
+ public void onAnimationStart(Animation animation) {
+ // Slide the bottom nav on animation start so it's (not) visible when the dialpad
+ // finishes animating down.
+ if (bottomNavVisible) {
+ showBottomNav();
+ } else {
+ hideBottomNav();
+ }
+ }
@Override
public void onAnimationEnd(Animation animation) {
@@ -196,16 +257,30 @@ public final class MainActivity extends AppCompatActivity
});
}
+ private void hideBottomNav() {
+ bottomNav.setVisibility(View.INVISIBLE);
+ if (bottomNav.getHeight() == 0) {
+ ViewUtil.doOnGlobalLayout(bottomNav, v -> fab.setTranslationY(bottomNav.getHeight()));
+ } else {
+ fab.setTranslationY(bottomNav.getHeight());
+ }
+ }
+
+ private void showBottomNav() {
+ bottomNav.setVisibility(View.VISIBLE);
+ fab.setTranslationY(0);
+ }
+
/**
* Should be called when the user presses the back button.
*
- * @return true if {@link #onBackPressed()} handled to action.
+ * @return true if #onBackPressed() handled to action.
*/
public boolean onBackPressed() {
- if (isDialpadVisible && !TextUtils.isEmpty(getDialpadFragment().getQuery())) {
- hideDialpad(true);
+ if (isDialpadVisible() && !TextUtils.isEmpty(getDialpadFragment().getQuery())) {
+ hideDialpad(/* animate=*/ true, /* bottomNavVisible=*/ false);
return true;
- } else if (isSearchVisible) {
+ } else if (isSearchVisible()) {
closeSearch(true);
return true;
} else {
@@ -213,14 +288,17 @@ public final class MainActivity extends AppCompatActivity
}
}
- /** Calls {@link #hideDialpad(boolean)} and removes the search fragment. */
+ /** Calls {@link #hideDialpad(boolean, boolean)} and removes the search fragment. */
private void closeSearch(boolean animate) {
- Assert.checkArgument(isSearchVisible);
- if (isDialpadVisible) {
- hideDialpad(animate);
+ Assert.checkArgument(isSearchVisible());
+ if (isDialpadVisible()) {
+ hideDialpad(animate, /* bottomNavVisible=*/ true);
+ } else if (!fab.isShown()) {
+ fab.show();
}
+ showBottomNav();
+ toolbar.collapse(animate);
getFragmentManager().beginTransaction().remove(getSearchFragment()).commit();
- isSearchVisible = false;
}
private DialpadFragment getDialpadFragment() {
@@ -230,19 +308,49 @@ public final class MainActivity extends AppCompatActivity
private NewSearchFragment getSearchFragment() {
return (NewSearchFragment) getFragmentManager().findFragmentByTag(SEARCH_FRAGMENT_TAG);
}
- }
- /**
- * Implementation of {@link SearchBarListener} that holds the logic for how to handle search bar
- * events.
- */
- private static final class MainSearchBarListener implements SearchBarListener {
+ private boolean isDialpadVisible() {
+ DialpadFragment fragment = getDialpadFragment();
+ return fragment != null
+ && fragment.isAdded()
+ && !fragment.isHidden()
+ && fragment.isDialpadSlideUp();
+ }
+
+ private boolean isSearchVisible() {
+ NewSearchFragment fragment = getSearchFragment();
+ return fragment != null && fragment.isAdded() && !fragment.isHidden();
+ }
+ /**
+ * Opens search in regular/search bar search mode.
+ *
+ * <p>Hides fab, expands toolbar and starts the search fragment.
+ */
@Override
- public void onSearchQueryUpdated(String query) {}
+ public void onSearchBarClicked() {
+ fab.hide();
+ toolbar.expand(/* animate=*/ true, Optional.absent());
+
+ android.app.FragmentTransaction transaction = getFragmentManager().beginTransaction();
+
+ // Show Search
+ if (getSearchFragment() == null) {
+ NewSearchFragment searchFragment = NewSearchFragment.newInstance(false);
+ transaction.add(R.id.search_fragment_container, searchFragment, SEARCH_FRAGMENT_TAG);
+ } else if (!isSearchVisible()) {
+ transaction.show(getSearchFragment());
+ }
+ transaction.commit();
+ }
+
+ @Override
+ public void onSearchBackButtonClicked() {
+ closeSearch(true);
+ }
@Override
- public void onSearchBackButtonClicked() {}
+ public void onSearchQueryUpdated(String query) {}
@Override
public void onVoiceButtonClicked(VoiceSearchResultCallback voiceSearchResultCallback) {}
diff --git a/java/com/android/dialer/main/impl/res/layout/main_activity.xml b/java/com/android/dialer/main/impl/res/layout/main_activity.xml
index 0b0652af5..eb0d45e57 100644
--- a/java/com/android/dialer/main/impl/res/layout/main_activity.xml
+++ b/java/com/android/dialer/main/impl/res/layout/main_activity.xml
@@ -37,13 +37,20 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/>
- <!-- Holds search and dialpad fragments -->
+ <!-- Holds search fragment -->
<FrameLayout
android:id="@+id/search_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/toolbar"/>
+ <!-- Holds Dialpad fragment -->
+ <FrameLayout
+ android:id="@+id/dialpad_fragment_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:elevation="10dp"/>
+
<!-- MainToolbar -->
<include
android:id="@+id/toolbar"
diff --git a/java/com/android/dialer/main/impl/toolbar/MainToolbar.java b/java/com/android/dialer/main/impl/toolbar/MainToolbar.java
index b32217230..388815a1e 100644
--- a/java/com/android/dialer/main/impl/toolbar/MainToolbar.java
+++ b/java/com/android/dialer/main/impl/toolbar/MainToolbar.java
@@ -25,6 +25,8 @@ import android.view.MenuItem;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageButton;
import com.android.dialer.common.Assert;
+import com.android.dialer.util.ViewUtil;
+import com.google.common.base.Optional;
/** Toolbar for {@link com.android.dialer.main.impl.MainActivity}. */
public final class MainToolbar extends Toolbar implements OnMenuItemClickListener {
@@ -33,6 +35,7 @@ public final class MainToolbar extends Toolbar implements OnMenuItemClickListene
private static final AccelerateDecelerateInterpolator SLIDE_INTERPOLATOR =
new AccelerateDecelerateInterpolator();
+ private SearchBarView searchBar;
private SearchBarListener listener;
private boolean isSlideUp;
@@ -49,6 +52,8 @@ public final class MainToolbar extends Toolbar implements OnMenuItemClickListene
overflowMenu.setOnMenuItemClickListener(this);
optionsMenuButton.setOnClickListener(v -> overflowMenu.show());
optionsMenuButton.setOnTouchListener(overflowMenu.getDragToOpenListener());
+
+ searchBar = findViewById(R.id.search_view_container);
}
@Override
@@ -69,6 +74,10 @@ public final class MainToolbar extends Toolbar implements OnMenuItemClickListene
/** Slides the toolbar up and off the screen. */
public void slideUp(boolean animate) {
Assert.checkArgument(!isSlideUp);
+ if (getHeight() == 0) {
+ ViewUtil.doOnGlobalLayout(this, view -> slideUp(animate));
+ return;
+ }
isSlideUp = true;
animate()
.translationY(-getHeight())
@@ -77,11 +86,7 @@ public final class MainToolbar extends Toolbar implements OnMenuItemClickListene
.start();
}
- /**
- * Slides the toolbar down and back onto the screen.
- *
- * @param animate
- */
+ /** Slides the toolbar down and back onto the screen. */
public void slideDown(boolean animate) {
Assert.checkArgument(isSlideUp);
isSlideUp = false;
@@ -92,6 +97,16 @@ public final class MainToolbar extends Toolbar implements OnMenuItemClickListene
.start();
}
+ /** @see SearchBarView#collapse(boolean) */
+ public void collapse(boolean animate) {
+ searchBar.collapse(animate);
+ }
+
+ /** @see SearchBarView#collapse(boolean) */
+ public void expand(boolean animate, Optional<String> text) {
+ searchBar.expand(animate, text);
+ }
+
@VisibleForTesting
public boolean isSlideUp() {
return isSlideUp;
diff --git a/java/com/android/dialer/main/impl/toolbar/SearchBarListener.java b/java/com/android/dialer/main/impl/toolbar/SearchBarListener.java
index 32258d95b..2e31997e6 100644
--- a/java/com/android/dialer/main/impl/toolbar/SearchBarListener.java
+++ b/java/com/android/dialer/main/impl/toolbar/SearchBarListener.java
@@ -19,6 +19,9 @@ package com.android.dialer.main.impl.toolbar;
/** Useful callback for {@link SearchBarView} listeners. */
public interface SearchBarListener {
+ /** Called when the user clicks on the search bar. */
+ void onSearchBarClicked();
+
/** Called when the search query updates. */
void onSearchQueryUpdated(String query);
diff --git a/java/com/android/dialer/main/impl/toolbar/SearchBarView.java b/java/com/android/dialer/main/impl/toolbar/SearchBarView.java
index 35c3cee16..306a5bb4e 100644
--- a/java/com/android/dialer/main/impl/toolbar/SearchBarView.java
+++ b/java/com/android/dialer/main/impl/toolbar/SearchBarView.java
@@ -66,7 +66,7 @@ final class SearchBarView extends FrameLayout {
searchBoxCollapsed = findViewById(R.id.search_box_collapsed);
searchBoxExpanded = findViewById(R.id.search_box_expanded);
- setOnClickListener(v -> expand(true, Optional.absent()));
+ setOnClickListener(v -> listener.onSearchBarClicked());
findViewById(R.id.voice_search_button).setOnClickListener(v -> voiceSearchClicked());
findViewById(R.id.search_back_button).setOnClickListener(v -> onSearchBackButtonClicked());
clearButton.setOnClickListener(v -> onSearchClearButtonClicked());
@@ -92,7 +92,7 @@ final class SearchBarView extends FrameLayout {
}
/** Expand the search bar and populate it with text if any exists. */
- private void expand(boolean animate, Optional<String> text) {
+ /* package-private */ void expand(boolean animate, Optional<String> text) {
if (isExpanded) {
return;
}
@@ -126,7 +126,7 @@ final class SearchBarView extends FrameLayout {
}
/** Collapse the search bar and clear it's text. */
- private void collapse(boolean animate) {
+ /* package-private */ void collapse(boolean animate) {
if (!isExpanded) {
return;
}
@@ -173,7 +173,7 @@ final class SearchBarView extends FrameLayout {
requestLayout();
}
- public void setSearchBarListener(SearchBarListener listener) {
+ /* package-private */ void setSearchBarListener(SearchBarListener listener) {
this.listener = listener;
}
diff --git a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
index 1e630488d..e8a8a4e06 100644
--- a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
+++ b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
@@ -490,9 +490,9 @@ public final class NewSearchFragment extends Fragment
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
v.performClick();
+ FragmentUtils.getParentUnsafe(this, SearchFragmentListener.class).onSearchListTouch();
}
- return FragmentUtils.getParentUnsafe(this, SearchFragmentListener.class)
- .onSearchListTouch(event);
+ return false;
}
@Override
@@ -540,12 +540,8 @@ public final class NewSearchFragment extends Fragment
/** Callback to {@link NewSearchFragment}'s parent to be notified of important events. */
public interface SearchFragmentListener {
- /**
- * Called when the list view in {@link NewSearchFragment} is touched.
- *
- * @see OnTouchListener#onTouch(View, MotionEvent)
- */
- boolean onSearchListTouch(MotionEvent event);
+ /** Called when the list view in {@link NewSearchFragment} is clicked. */
+ void onSearchListTouch();
/** Called when a call is placed from the search fragment. */
void onCallPlacedFromSearch();