Merge "Fixed regression with search not reacting properly to on touch events."
diff --git a/java/com/android/dialer/dialpadview/DialpadFragment.java b/java/com/android/dialer/dialpadview/DialpadFragment.java
index 2796fca..9cee7bc 100644
--- a/java/com/android/dialer/dialpadview/DialpadFragment.java
+++ b/java/com/android/dialer/dialpadview/DialpadFragment.java
@@ -59,7 +59,6 @@
 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;
@@ -415,7 +414,7 @@
         .setOnTouchListener(
             (v, event) -> {
               if (isDigitsEmpty()) {
-                if (getActivity() != null && event.getAction() == MotionEvent.ACTION_UP) {
+                if (getActivity() != null) {
                   LogUtil.i("DialpadFragment.onCreateView", "dialpad spacer touched");
                   return ((HostInterface) getActivity()).onDialpadSpacerTouchWithEmptyQuery();
                 }
diff --git a/java/com/android/dialer/main/impl/MainActivity.java b/java/com/android/dialer/main/impl/MainActivity.java
index 35597f9..7aae8cb 100644
--- a/java/com/android/dialer/main/impl/MainActivity.java
+++ b/java/com/android/dialer/main/impl/MainActivity.java
@@ -157,13 +157,13 @@
 
   @Override // DialpadFragment.HostInterface
   public boolean onDialpadSpacerTouchWithEmptyQuery() {
-    searchController.onBackPressed();
-    return true;
+    // No-op, just let the clicks fall through to the search list
+    return false;
   }
 
   @Override // SearchFragmentListener
   public void onSearchListTouch() {
-    searchController.onBackPressed();
+    searchController.onSearchListTouch();
   }
 
   @Override // SearchFragmentListener
diff --git a/java/com/android/dialer/main/impl/MainSearchController.java b/java/com/android/dialer/main/impl/MainSearchController.java
index 4cccbf4..76c93bb 100644
--- a/java/com/android/dialer/main/impl/MainSearchController.java
+++ b/java/com/android/dialer/main/impl/MainSearchController.java
@@ -16,6 +16,7 @@
 
 package com.android.dialer.main.impl;
 
+import android.app.FragmentTransaction;
 import android.support.annotation.Nullable;
 import android.support.design.widget.FloatingActionButton;
 import android.text.TextUtils;
@@ -24,12 +25,14 @@
 import android.view.animation.Animation.AnimationListener;
 import com.android.dialer.callintent.CallInitiationType;
 import com.android.dialer.common.Assert;
+import com.android.dialer.common.LogUtil;
 import com.android.dialer.dialpadview.DialpadFragment;
 import com.android.dialer.dialpadview.DialpadFragment.DialpadListener;
 import com.android.dialer.dialpadview.DialpadFragment.OnDialpadQueryChangedListener;
 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.util.ViewUtil;
 import com.google.common.base.Optional;
 
@@ -77,8 +80,7 @@
     toolbar.expand(animate, Optional.absent());
     mainActivity.setTitle(R.string.dialpad_activity_title);
 
-    android.app.FragmentTransaction transaction =
-        mainActivity.getFragmentManager().beginTransaction();
+    FragmentTransaction transaction = mainActivity.getFragmentManager().beginTransaction();
 
     // Show Search
     if (getSearchFragment() == null) {
@@ -105,6 +107,7 @@
 
     fab.show();
     toolbar.slideDown(animate);
+    toolbar.transferQueryFromDialpad(getDialpadFragment().getQuery());
     mainActivity.setTitle(R.string.main_activity_label);
 
     DialpadFragment dialpadFragment = getDialpadFragment();
@@ -155,15 +158,43 @@
   }
 
   /**
+   * @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() {
+    if (isDialpadVisible()) {
+      if (TextUtils.isEmpty(getDialpadFragment().getQuery())) {
+        closeSearch(true);
+      } else {
+        hideDialpad(/* animate=*/ true, /* bottomNavVisible=*/ false);
+      }
+    } else if (isSearchVisible()) {
+      if (TextUtils.isEmpty(toolbar.getQuery())) {
+        closeSearch(true);
+      } else {
+        toolbar.hideKeyboard();
+      }
+    }
+  }
+
+  /**
    * Should be called when the user presses the back button.
    *
    * @return true if #onBackPressed() handled to action.
    */
   public boolean onBackPressed() {
     if (isDialpadVisible() && !TextUtils.isEmpty(getDialpadFragment().getQuery())) {
+      LogUtil.i("MainSearchController#onBackPressed", "Dialpad visible with query");
       hideDialpad(/* animate=*/ true, /* bottomNavVisible=*/ false);
       return true;
     } else if (isSearchVisible()) {
+      LogUtil.i("MainSearchController#onBackPressed", "Search is visible");
       closeSearch(true);
       return true;
     } else {
@@ -218,9 +249,10 @@
   public void onSearchBarClicked() {
     fab.hide();
     toolbar.expand(/* animate=*/ true, Optional.absent());
+    toolbar.showKeyboard();
+    hideBottomNav();
 
-    android.app.FragmentTransaction transaction =
-        mainActivity.getFragmentManager().beginTransaction();
+    FragmentTransaction transaction = mainActivity.getFragmentManager().beginTransaction();
 
     // Show Search
     if (getSearchFragment() == null) {
diff --git a/java/com/android/dialer/main/impl/toolbar/MainToolbar.java b/java/com/android/dialer/main/impl/toolbar/MainToolbar.java
index 388815a..6e38d2e 100644
--- a/java/com/android/dialer/main/impl/toolbar/MainToolbar.java
+++ b/java/com/android/dialer/main/impl/toolbar/MainToolbar.java
@@ -111,4 +111,20 @@
   public boolean isSlideUp() {
     return isSlideUp;
   }
+
+  public String getQuery() {
+    return searchBar.getQuery();
+  }
+
+  public void transferQueryFromDialpad(String query) {
+    searchBar.setQueryWithoutUpdate(query);
+  }
+
+  public void hideKeyboard() {
+    searchBar.hideKeyboard();
+  }
+
+  public void showKeyboard() {
+    searchBar.showKeyboard();
+  }
 }
diff --git a/java/com/android/dialer/main/impl/toolbar/SearchBarView.java b/java/com/android/dialer/main/impl/toolbar/SearchBarView.java
index 306a5bb..6b9f39d 100644
--- a/java/com/android/dialer/main/impl/toolbar/SearchBarView.java
+++ b/java/com/android/dialer/main/impl/toolbar/SearchBarView.java
@@ -30,6 +30,7 @@
 import android.widget.EditText;
 import android.widget.FrameLayout;
 import com.android.dialer.animation.AnimUtils;
+import com.android.dialer.common.UiUtil;
 import com.android.dialer.util.DialerUtils;
 import com.google.common.base.Optional;
 
@@ -44,6 +45,9 @@
 
   private SearchBarListener listener;
   private EditText searchBox;
+  // This useful for when the query didn't actually change. We want to avoid making excessive calls
+  // where we can since IPCs can take a long time on slow networks.
+  private boolean skipLatestTextChange;
 
   private int initialHeight;
   private boolean isExpanded;
@@ -177,6 +181,24 @@
     this.listener = listener;
   }
 
+  public String getQuery() {
+    return searchBox.getText().toString();
+  }
+
+  public void setQueryWithoutUpdate(String query) {
+    skipLatestTextChange = true;
+    searchBox.setText(query);
+    searchBox.setSelection(searchBox.getText().length());
+  }
+
+  public void hideKeyboard() {
+    UiUtil.hideKeyboardFrom(getContext(), searchBox);
+  }
+
+  public void showKeyboard() {
+    UiUtil.openKeyboardFrom(getContext(), searchBox);
+  }
+
   /** Handles logic for text changes in the search box. */
   private class SearchBoxTextWatcher implements TextWatcher {
 
@@ -189,6 +211,11 @@
     @Override
     public void afterTextChanged(Editable s) {
       clearButton.setVisibility(TextUtils.isEmpty(s) ? GONE : VISIBLE);
+      if (skipLatestTextChange) {
+        skipLatestTextChange = false;
+        return;
+      }
+
       listener.onSearchQueryUpdated(s.toString());
     }
   }
diff --git a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
index e8a8a4e..30949d3 100644
--- a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
+++ b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
@@ -490,8 +490,8 @@
   public boolean onTouch(View v, MotionEvent event) {
     if (event.getAction() == MotionEvent.ACTION_UP) {
       v.performClick();
-      FragmentUtils.getParentUnsafe(this, SearchFragmentListener.class).onSearchListTouch();
     }
+    FragmentUtils.getParentUnsafe(this, SearchFragmentListener.class).onSearchListTouch();
     return false;
   }