Timezone picker UI improvements on rotation

Bug: 8643739
Change-Id: I92e25ffd8cf8fe7393ba6fcfdd725a26e2063bda
diff --git a/src/com/android/timezonepicker/TimeZoneFilterTypeAdapter.java b/src/com/android/timezonepicker/TimeZoneFilterTypeAdapter.java
index ffc699b..0303cab 100644
--- a/src/com/android/timezonepicker/TimeZoneFilterTypeAdapter.java
+++ b/src/com/android/timezonepicker/TimeZoneFilterTypeAdapter.java
@@ -33,6 +33,8 @@
 public class TimeZoneFilterTypeAdapter extends BaseAdapter implements Filterable, OnClickListener {
     public static final String TAG = "TimeZoneFilterTypeAdapter";
 
+    private static final boolean DEBUG = false;
+
     public static final int FILTER_TYPE_EMPTY = -1;
     public static final int FILTER_TYPE_NONE = 0;
     public static final int FILTER_TYPE_COUNTRY = 1;
@@ -163,7 +165,9 @@
     private class ArrayFilter extends Filter {
         @Override
         protected FilterResults performFiltering(CharSequence prefix) {
-            Log.e(TAG, "performFiltering >>>> [" + prefix + "]");
+            if (DEBUG) {
+                Log.d(TAG, "performFiltering >>>> [" + prefix + "]");
+            }
 
             FilterResults results = new FilterResults();
             String prefixString = null;
@@ -233,7 +237,9 @@
             // ////////////////////////////////////////
             // TODO Search by state
             // ////////////////////////////////////////
-            Log.e(TAG, "performFiltering <<<< " + filtered.size() + "[" + prefix + "]");
+            if (DEBUG) {
+                Log.d(TAG, "performFiltering <<<< " + filtered.size() + "[" + prefix + "]");
+            }
 
             results.values = filtered;
             results.count = filtered.size();
@@ -369,7 +375,9 @@
                 return Integer.MIN_VALUE;
             }
 
-            Log.e(TAG, "Parsing " + str + " -> " + negativeMultiplier * num);
+            if (DEBUG) {
+                Log.d(TAG, "Parsing " + str + " -> " + negativeMultiplier * num);
+            }
             return negativeMultiplier * num;
         }
 
@@ -387,11 +395,15 @@
                     }
                     mListener.onSetFilter(filterType, null, 0);
                 }
-                Log.e(TAG, "publishResults: " + results.count + " of null [" + constraint);
+                if (DEBUG) {
+                    Log.d(TAG, "publishResults: " + results.count + " of null [" + constraint);
+                }
             } else {
                 mLiveResults = (ArrayList<FilterTypeResult>) results.values;
-                Log.e(TAG, "publishResults: " + results.count + " of " + mLiveResults.size() + " ["
-                        + constraint);
+                if (DEBUG) {
+                    Log.d(TAG, "publishResults: " + results.count + " of " + mLiveResults.size()
+                            + " [" + constraint);
+                }
             }
             mLiveResultsCount = results.count;
 
diff --git a/src/com/android/timezonepicker/TimeZonePickerDialog.java b/src/com/android/timezonepicker/TimeZonePickerDialog.java
index 4977be3..d00513e 100644
--- a/src/com/android/timezonepicker/TimeZonePickerDialog.java
+++ b/src/com/android/timezonepicker/TimeZonePickerDialog.java
@@ -30,7 +30,15 @@
     public static final String BUNDLE_START_TIME_MILLIS = "bundle_event_start_time";
     public static final String BUNDLE_TIME_ZONE = "bundle_event_time_zone";
 
+    private static final String KEY_HAS_RESULTS = "has_results";
+    private static final String KEY_LAST_FILTER_STRING = "last_filter_string";
+    private static final String KEY_LAST_FILTER_TYPE = "last_filter_type";
+    private static final String KEY_LAST_FILTER_TIME = "last_filter_time";
+    private static final String KEY_HIDE_FILTER_SEARCH = "hide_filter_search";
+
     private OnTimeZoneSetListener mTimeZoneSetListener;
+    private TimeZonePickerView mView;
+    private boolean mHasCachedResults = false;
 
     public interface OnTimeZoneSetListener {
         void onTimeZoneSet(TimeZoneInfo tzi);
@@ -54,7 +62,31 @@
             timeMillis = b.getLong(BUNDLE_START_TIME_MILLIS);
             timeZone = b.getString(BUNDLE_TIME_ZONE);
         }
-        return new TimeZonePickerView(getActivity(), null, timeZone, timeMillis, this);
+        boolean hideFilterSearch = false;
+
+        if (savedInstanceState != null) {
+            hideFilterSearch = savedInstanceState.getBoolean(KEY_HIDE_FILTER_SEARCH);
+        }
+        mView = new TimeZonePickerView(getActivity(), null, timeZone, timeMillis, this,
+                hideFilterSearch);
+        if (savedInstanceState != null && savedInstanceState.getBoolean(KEY_HAS_RESULTS, false)) {
+            mView.showFilterResults(savedInstanceState.getInt(KEY_LAST_FILTER_TYPE),
+                                    savedInstanceState.getString(KEY_LAST_FILTER_STRING),
+                                    savedInstanceState.getInt(KEY_LAST_FILTER_TIME));
+        }
+        return mView;
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putBoolean(KEY_HAS_RESULTS, mView != null && mView.hasResults());
+        if (mView != null) {
+            outState.putInt(KEY_LAST_FILTER_TYPE, mView.getLastFilterType());
+            outState.putString(KEY_LAST_FILTER_STRING, mView.getLastFilterString());
+            outState.putInt(KEY_LAST_FILTER_TIME, mView.getLastFilterTime());
+            outState.putBoolean(KEY_HIDE_FILTER_SEARCH, mView.getHideFilterSearchOnStart());
+        }
     }
 
     @Override
diff --git a/src/com/android/timezonepicker/TimeZonePickerView.java b/src/com/android/timezonepicker/TimeZonePickerView.java
index e41db2b..a56d95b 100644
--- a/src/com/android/timezonepicker/TimeZonePickerView.java
+++ b/src/com/android/timezonepicker/TimeZonePickerView.java
@@ -26,6 +26,7 @@
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.View.OnClickListener;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AutoCompleteTextView;
@@ -33,12 +34,15 @@
 import android.widget.LinearLayout;
 import android.widget.ListView;
 
-public class TimeZonePickerView extends LinearLayout implements TextWatcher, OnItemClickListener {
+public class TimeZonePickerView extends LinearLayout implements TextWatcher, OnItemClickListener,
+    OnClickListener {
     private static final String TAG = "TimeZonePickerView";
 
     private Context mContext;
     private AutoCompleteTextView mAutoCompleteTextView;
     private TimeZoneFilterTypeAdapter mFilterAdapter;
+    private boolean mHideFilterSearchOnStart = false;
+    private boolean mFirstTime = true;
     TimeZoneResultAdapter mResultAdapter;
 
     private ImageButton mClearButton;
@@ -48,13 +52,16 @@
     }
 
     public TimeZonePickerView(Context context, AttributeSet attrs,
-            String timeZone, long timeMillis, OnTimeZoneSetListener l) {
+            String timeZone, long timeMillis, OnTimeZoneSetListener l,
+            boolean hideFilterSearch) {
         super(context, attrs);
         mContext = context;
         LayoutInflater inflater = (LayoutInflater) context.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         inflater.inflate(R.layout.timezonepickerview, this, true);
 
+        mHideFilterSearchOnStart = hideFilterSearch;
+
         TimeZoneData tzd = new TimeZoneData(mContext, timeZone, timeMillis);
 
         mResultAdapter = new TimeZoneResultAdapter(mContext, tzd, l);
@@ -62,11 +69,12 @@
         timeZoneList.setAdapter(mResultAdapter);
         timeZoneList.setOnItemClickListener(mResultAdapter);
 
-        mAutoCompleteTextView = (AutoCompleteTextView) findViewById(R.id.searchBox);
         mFilterAdapter = new TimeZoneFilterTypeAdapter(mContext, tzd, mResultAdapter);
-        mAutoCompleteTextView.setAdapter(mFilterAdapter);
+
+        mAutoCompleteTextView = (AutoCompleteTextView) findViewById(R.id.searchBox);
         mAutoCompleteTextView.addTextChangedListener(this);
         mAutoCompleteTextView.setOnItemClickListener(this);
+        mAutoCompleteTextView.setOnClickListener(this);
 
         updateHint(R.string.hint_time_zone_search, R.drawable.ic_search_holo_light);
         mClearButton = (ImageButton) findViewById(R.id.clear_search);
@@ -78,6 +86,32 @@
         });
     }
 
+    public void showFilterResults(int type, String string, int time) {
+        if (mResultAdapter != null) {
+            mResultAdapter.onSetFilter(type, string, time);
+        }
+    }
+
+    public boolean hasResults() {
+        return mResultAdapter != null && mResultAdapter.hasResults();
+    }
+
+    public int getLastFilterType() {
+        return mResultAdapter != null ? mResultAdapter.getLastFilterType() : -1;
+    }
+
+    public String getLastFilterString() {
+        return mResultAdapter != null ? mResultAdapter.getLastFilterString() : null;
+    }
+
+    public int getLastFilterTime() {
+        return mResultAdapter != null ? mResultAdapter.getLastFilterType() : -1;
+    }
+
+    public boolean getHideFilterSearchOnStart() {
+        return mHideFilterSearchOnStart;
+    }
+
     private void updateHint(int hintTextId, int imageDrawableId) {
         String hintText = getResources().getString(hintTextId);
         Drawable searchIcon = getResources().getDrawable(imageDrawableId);
@@ -98,7 +132,11 @@
     // Implementation of TextWatcher
     @Override
     public void onTextChanged(CharSequence s, int start, int before, int count) {
-        mFilterAdapter.getFilter().filter(s.toString());
+        if (mFirstTime && mHideFilterSearchOnStart) {
+            mFirstTime = false;
+            return;
+        }
+        filterOnString(s.toString());
     }
 
     // Implementation of TextWatcher
@@ -113,6 +151,25 @@
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
         // An onClickListener for the view item because I haven't figured out a
         // way to update the AutoCompleteTextView without causing an infinite loop.
+        mHideFilterSearchOnStart = true;
         mFilterAdapter.onClick(view);
     }
+
+    @Override
+    public void onClick(View v) {
+        if (mAutoCompleteTextView != null && !mAutoCompleteTextView.isPopupShowing()) {
+            filterOnString(mAutoCompleteTextView.getText().toString());
+        }
+    }
+
+    // This method will set the adapter if no adapter has been set.  The adapter is initialized
+    // here to prevent the drop-down from appearing uninvited on orientation change, as the
+    // AutoCompleteTextView.setText() will trigger the drop-down if the adapter has been set.
+    private void filterOnString(String string) {
+        if (mAutoCompleteTextView.getAdapter() == null) {
+            mAutoCompleteTextView.setAdapter(mFilterAdapter);
+        }
+        mHideFilterSearchOnStart = false;
+        mFilterAdapter.getFilter().filter(string);
+    }
 }
diff --git a/src/com/android/timezonepicker/TimeZoneResultAdapter.java b/src/com/android/timezonepicker/TimeZoneResultAdapter.java
index 2b57f39..efc275e 100644
--- a/src/com/android/timezonepicker/TimeZoneResultAdapter.java
+++ b/src/com/android/timezonepicker/TimeZoneResultAdapter.java
@@ -38,12 +38,19 @@
 public class TimeZoneResultAdapter extends BaseAdapter implements OnItemClickListener,
         OnSetFilterListener {
     private static final String TAG = "TimeZoneResultAdapter";
+    private static final boolean DEBUG = false;
     private static final int VIEW_TAG_TIME_ZONE = R.id.time_zone;
 
     /** SharedPref name and key for recent time zones */
     private static final String SHARED_PREFS_NAME = "com.android.calendar_preferences";
     private static final String KEY_RECENT_TIMEZONES = "preferences_recent_timezones";
 
+    private int mLastFilterType;
+    private String mLastFilterString;
+    private int mLastFilterTime;
+
+    private boolean mHasResults = false;
+
     /**
      * The delimiter we use when serializing recent timezones to shared
      * preferences
@@ -91,10 +98,32 @@
         onSetFilter(TimeZoneFilterTypeAdapter.FILTER_TYPE_NONE, null, 0);
     }
 
+    public boolean hasResults() {
+        return mHasResults;
+    }
+
+    public int getLastFilterType() {
+        return mLastFilterType;
+    }
+
+    public String getLastFilterString() {
+        return mLastFilterString;
+    }
+
+    public int getLastFilterTime() {
+        return mLastFilterTime;
+    }
+
     // Implements OnSetFilterListener
     @Override
     public void onSetFilter(int filterType, String str, int time) {
-        Log.d(TAG, "onSetFilter: " + filterType + " [" + str + "] " + time);
+        if (DEBUG) {
+            Log.d(TAG, "onSetFilter: " + filterType + " [" + str + "] " + time);
+        }
+
+        mLastFilterType = filterType;
+        mLastFilterString = str;
+        mLastFilterTime = time;
 
         mFilteredTimeZoneLength = 0;
         int idx = 0;
@@ -149,6 +178,8 @@
             default:
                 throw new IllegalArgumentException();
         }
+        mHasResults = mFilteredTimeZoneLength > 0;
+
         notifyDataSetChanged();
     }