From c1717ac3a92016cdfc80b5e61413ecfc41b45298 Mon Sep 17 00:00:00 2001 From: uabdullah Date: Wed, 17 Jan 2018 11:23:05 -0800 Subject: Take voicemail alert position into account for "older" header for NUI Voicemail Tab The older header must take into account and be offset when there is a voicemail alert being shown. Bug: 71700117 Test: N/A PiperOrigin-RevId: 182243160 Change-Id: Ib38ba82e75fedf9a2939078447e4791f5239524c --- java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'java/com') diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java index 32c5b6991..86d386050 100644 --- a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java +++ b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java @@ -150,7 +150,7 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter this.olderHeaderPosition = Integer.MAX_VALUE; // Didn't find any "Older" rows. } else { this.todayHeaderPosition = Integer.MAX_VALUE; // Didn't find any "Today" rows. - this.olderHeaderPosition = 0; + this.olderHeaderPosition = 0 + alertOffSet; } } else { // There are no rows, just need to set these because they are final. this.todayHeaderPosition = Integer.MAX_VALUE; -- cgit v1.2.3 From 70a4b0929d8223ef0dc55b0f1b3790a892bb9043 Mon Sep 17 00:00:00 2001 From: calderwoodra Date: Wed, 17 Jan 2018 13:17:27 -0800 Subject: Updated toolbar and dialpad interactions in NUI. Toolbar, Dialpad, Bottom Nav, FAB and Search now all show and hide properly according to the state of the application. Follow up CLs will include: - saving/restoring state - sending query to search fragment to display results Bug: 181512198 Test: MainActivityIntegrationTest PiperOrigin-RevId: 182259200 Change-Id: I1309d8df2a5425bf051e52a459a1f78e1157fe08 --- java/com/android/dialer/app/DialtactsActivity.java | 4 +- .../dialer/dialpadview/DialpadFragment.java | 10 +- .../com/android/dialer/main/impl/MainActivity.java | 180 ++++++++++++++++----- .../dialer/main/impl/res/layout/main_activity.xml | 9 +- .../dialer/main/impl/toolbar/MainToolbar.java | 25 ++- .../main/impl/toolbar/SearchBarListener.java | 3 + .../dialer/main/impl/toolbar/SearchBarView.java | 8 +- .../searchfragment/list/NewSearchFragment.java | 12 +- 8 files changed, 193 insertions(+), 58 deletions(-) (limited to 'java/com') 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 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. + * + *

Components modified are: + * + *

    + *
  • Bottom Nav Bar, completely hidden when in search ui. + *
  • FAB, visible in dialpad search when dialpad is hidden. Otherwise, FAB is hidden. + *
  • Toolbar, expanded and visible when dialpad is hidden. Otherwise, hidden off screen. + *
  • Dialpad, shown through fab clicks and hidden with Android back button. + *
+ * + * @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. + * + *

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"/> - + + + + 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 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 text) { + /* package-private */ void expand(boolean animate, Optional 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(); -- cgit v1.2.3