Contact filter uses custom UI instead of NotifyingSpinner

Change-Id: Ia51c6944d67e41050be4e3e60856b15b77ffa090
diff --git a/res/layout/filter_spinner.xml b/res/layout/filter_spinner.xml
deleted file mode 100644
index 21c591f..0000000
--- a/res/layout/filter_spinner.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 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.
--->
-
-<view
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    class="com.android.contacts.list.FilterSpinnerItemView"
-    android:layout_height="wrap_content"
-    android:layout_width="match_parent"
-    android:gravity="left">
-
-    <ImageView
-        android:id="@+id/icon"
-        android:scaleType="fitCenter"
-        android:layout_width="24dip"
-        android:layout_height="24dip"
-        android:layout_marginLeft="8dip"
-    />
-
-    <TextView
-        android:id="@+id/label"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginLeft="8dip"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:gravity="center_vertical"
-        android:ellipsize="end"
-    />
-
-    <ImageView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginLeft="8dip"
-        android:layout_gravity="bottom"
-        android:src="@drawable/filter_selector_corner"
-    />
-</view>
-
diff --git a/res/layout/filter_spinner_item.xml b/res/layout/filter_spinner_item.xml
index b05a019..6573a30 100644
--- a/res/layout/filter_spinner_item.xml
+++ b/res/layout/filter_spinner_item.xml
@@ -16,7 +16,7 @@
 
 <view
     xmlns:android="http://schemas.android.com/apk/res/android"
-    class="com.android.contacts.list.FilterSpinnerItemView"
+    class="com.android.contacts.list.ContactListFilterView"
     android:layout_height="52dip"
     android:layout_width="fill_parent"
     android:paddingLeft="7dip"
diff --git a/res/layout/navigation_bar.xml b/res/layout/navigation_bar.xml
index c90f563..6286b1c 100644
--- a/res/layout/navigation_bar.xml
+++ b/res/layout/navigation_bar.xml
@@ -25,7 +25,8 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:paddingRight="10dip"
-        android:minWidth="240dip">
+        android:minWidth="240dip"
+        android:background="@drawable/filter_selector_background">
         <TextView
             android:id="@+id/search_label"
             android:layout_width="wrap_content"
@@ -34,12 +35,36 @@
             android:gravity="center_vertical" />
 
         <view
-            class="com.android.contacts.widget.NotifyingSpinner"
-            android:id="@+id/filter_spinner"
-            android:layout_width="wrap_content"
+            class="com.android.contacts.list.ContactListFilterView"
+            android:id="@+id/filter_view"
             android:layout_height="match_parent"
-            android:prompt="@string/list_filter_prompt"
-            android:background="@drawable/filter_selector_background" />
+            android:layout_width="match_parent"
+            android:gravity="center_vertical">
+
+            <ImageView
+                android:id="@+id/icon"
+                android:scaleType="fitCenter"
+                android:layout_width="24dip"
+                android:layout_height="24dip"
+                android:layout_marginLeft="8dip" />
+
+            <TextView
+                android:id="@+id/label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="8dip"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+                android:gravity="center_vertical"
+                android:ellipsize="end" />
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="8dip"
+                android:layout_gravity="bottom"
+                android:src="@drawable/filter_selector_corner" />
+        </view>
+
     </FrameLayout>
 
     <view
diff --git a/res/values-xlarge/styles.xml b/res/values-xlarge/styles.xml
index 1e06a44..8abb44c 100644
--- a/res/values-xlarge/styles.xml
+++ b/res/values-xlarge/styles.xml
@@ -34,6 +34,7 @@
         <item name="list_item_header_text_width">56dip</item>
         <item name="list_item_photo_size">64dip</item>
         <item name="list_item_prefix_highlight_color">#729a27</item>
+        <item name="contact_filter_popup_width">320dip</item>
     </style>
 
     <style name="ContactPickerTheme" parent="@android:Theme.Dialog">
diff --git a/res/values/styles.xml b/res/values/styles.xml
index b8d9c54..71b653a 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -100,6 +100,10 @@
         <item name="android:windowExitAnimation">@anim/dummy_animation</item>
     </style>
 
+    <declare-styleable name="ContactBrowser">
+        <attr name="contact_filter_popup_width" format="dimension"/>
+    </declare-styleable>
+
     <declare-styleable name="ContactListItemView">
         <!-- An attribute that specifies a custom drawable for the pressed state in the contact list-->
         <attr name="pressedBackground" format="reference"/>
@@ -117,7 +121,6 @@
         <attr name="list_item_header_text_width" format="dimension"/>
         <attr name="list_item_photo_size" format="dimension"/>
         <attr name="list_item_prefix_highlight_color" format="color"/>
-
     </declare-styleable>
 
     <declare-styleable name="MultiplePhonePickerItemView">
@@ -142,6 +145,7 @@
         <item name="list_item_header_text_width">56dip</item>
         <item name="list_item_photo_size">56dip</item>
         <item name="list_item_prefix_highlight_color">#729a27</item>
+        <item name="contact_filter_popup_width">320dip</item>
     </style>
 
     <style name="ContactPickerTheme" parent="@android:Theme">
diff --git a/src/com/android/contacts/activities/ActionBarAdapter.java b/src/com/android/contacts/activities/ActionBarAdapter.java
index f2181b3..ec36356 100644
--- a/src/com/android/contacts/activities/ActionBarAdapter.java
+++ b/src/com/android/contacts/activities/ActionBarAdapter.java
@@ -18,8 +18,8 @@
 
 import com.android.contacts.R;
 import com.android.contacts.list.ContactListFilterController;
+import com.android.contacts.list.ContactListFilterView;
 import com.android.contacts.list.ContactsRequest;
-import com.android.contacts.widget.NotifyingSpinner;
 
 import android.app.ActionBar;
 import android.content.Context;
@@ -59,7 +59,7 @@
     private final Context mContext;
 
     private Listener mListener;
-    private NotifyingSpinner mFilterSpinner;
+    private ContactListFilterView mFilterView;
 
     public ActionBarAdapter(Context context) {
         mContext = context;
@@ -80,7 +80,7 @@
         mNavigationBar = LayoutInflater.from(mContext).inflate(R.layout.navigation_bar, null);
         actionBar.setCustomNavigationMode(mNavigationBar);
 
-        mFilterSpinner = (NotifyingSpinner) mNavigationBar.findViewById(R.id.filter_spinner);
+        mFilterView = (ContactListFilterView) mNavigationBar.findViewById(R.id.filter_view);
         mSearchLabel = (TextView) mNavigationBar.findViewById(R.id.search_label);
         mSearchView = (SearchView) mNavigationBar.findViewById(R.id.search_view);
         mSearchView.setIconifiedByDefault(false);
@@ -97,7 +97,7 @@
     }
 
     public void setContactListFilterController(ContactListFilterController controller) {
-        controller.setFilterSpinner(mFilterSpinner);
+        controller.setFilterSpinner(mFilterView);
     }
 
     public boolean isSearchMode() {
@@ -126,10 +126,10 @@
     public void updateVisibility() {
         if (mSearchMode) {
             mSearchLabel.setVisibility(View.VISIBLE);
-            mFilterSpinner.setVisibility(View.GONE);
+            mFilterView.setVisibility(View.GONE);
         } else {
             mSearchLabel.setVisibility(View.GONE);
-            mFilterSpinner.setVisibility(View.VISIBLE);
+            mFilterView.setVisibility(View.VISIBLE);
         }
     }
 
diff --git a/src/com/android/contacts/list/ContactListFilterController.java b/src/com/android/contacts/list/ContactListFilterController.java
index d10faac..d9fddbd 100644
--- a/src/com/android/contacts/list/ContactListFilterController.java
+++ b/src/com/android/contacts/list/ContactListFilterController.java
@@ -16,7 +16,6 @@
 package com.android.contacts.list;
 
 import com.android.contacts.R;
-import com.android.contacts.widget.NotifyingSpinner;
 
 import android.app.Activity;
 import android.app.LoaderManager;
@@ -24,6 +23,7 @@
 import android.content.Context;
 import android.content.Loader;
 import android.content.SharedPreferences;
+import android.content.res.TypedArray;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -31,10 +31,13 @@
 import android.util.SparseArray;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.BaseAdapter;
+import android.widget.ListPopupWindow;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -43,8 +46,8 @@
  * Controls a list of {@link ContactListFilter}'s.
  */
 public class ContactListFilterController
-        implements NotifyingSpinner.SelectionListener, OnItemSelectedListener,
-        LoaderCallbacks<List<ContactListFilter>>{
+        implements
+        LoaderCallbacks<List<ContactListFilter>>, OnClickListener, OnItemClickListener {
 
     public interface ContactListFilterListener {
         void onContactListFiltersLoaded();
@@ -64,12 +67,13 @@
     private Context mContext;
     private LoaderManager mLoaderManager;
     private ContactListFilterListener mListener;
-
+    private ListPopupWindow mPopup;
+    private int mPopupWidth = -1;
     private SparseArray<ContactListFilter> mFilters;
     private ArrayList<ContactListFilter> mFilterList;
     private int mNextFilterId = 1;
-    private NotifyingSpinner mFilterSpinner;
-    private FilterSpinnerAdapter mFilterSpinnerAdapter;
+    private ContactListFilterView mFilterView;
+    private FilterListAdapter mFilterListAdapter;
     private ContactListFilter mFilter;
     private boolean mFiltersLoaded;
     private final Handler mHandler = new Handler() {
@@ -91,9 +95,9 @@
         mListener = listener;
     }
 
-    public void setFilterSpinner(NotifyingSpinner filterSpinner) {
-        mFilterSpinner = filterSpinner;
-        mFilterSpinner.setOnItemSelectedListener(this);
+    public void setFilterSpinner(ContactListFilterView filterSpinner) {
+        mFilterView = filterSpinner;
+        mFilterView.setOnClickListener(this);
     }
 
     public ContactListFilter getFilter() {
@@ -104,14 +108,6 @@
         return mFilterList;
     }
 
-    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-        setContactListFilter((int) id);
-    }
-
-    public void onNothingSelected(AdapterView<?> parent) {
-        setContactListFilter(0);
-    }
-
     public boolean isLoaded() {
         return mFiltersLoaded;
     }
@@ -193,11 +189,10 @@
             mFilter = getDefaultFilter();
         }
 
-        if (mFilterSpinnerAdapter == null) {
-            mFilterSpinnerAdapter = new FilterSpinnerAdapter();
-            mFilterSpinner.setAdapter(mFilterSpinnerAdapter);
+        if (mFilterListAdapter == null) {
+            mFilterListAdapter = new FilterListAdapter();
         } else {
-            mFilterSpinnerAdapter.notifyDataSetChanged();
+            mFilterListAdapter.notifyDataSetChanged();
         }
 
         if (filterChanged) {
@@ -240,10 +235,38 @@
     }
 
     @Override
-    public void onSetSelection(NotifyingSpinner spinner, int position) {
-        ContactListFilter filter = mFilters.valueAt(position);
-        if (filter.filterType == ContactListFilter.FILTER_TYPE_CUSTOM) {
+    public void onClick(View v) {
+        if (!mFiltersLoaded) {
+            return;
+        }
+
+        if (mPopupWidth == -1) {
+            TypedArray a = mContext.obtainStyledAttributes(null, R.styleable.ContactBrowser);
+            mPopupWidth = a.getDimensionPixelSize(
+                    R.styleable.ContactBrowser_contact_filter_popup_width, -1);
+            a.recycle();
+
+            if (mPopupWidth == -1) {
+                mPopupWidth = mFilterView.getWidth();
+            }
+        }
+
+        mPopup = new ListPopupWindow(mContext, null);
+        mPopup.setWidth(mPopupWidth);
+        mPopup.setAdapter(mFilterListAdapter);
+        mPopup.setAnchorView(mFilterView);
+        mPopup.setOnItemClickListener(this);
+        mPopup.setModal(true);
+        mPopup.show();
+    }
+
+    @Override
+    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+        mPopup.dismiss();
+        if (mFilters.get((int) id).filterType == ContactListFilter.FILTER_TYPE_CUSTOM) {
             mListener.onContactListFilterCustomizationRequest();
+        } else {
+            setContactListFilter((int) id);
         }
     }
 
@@ -259,24 +282,15 @@
 
     protected void updateFilterView() {
         if (mFiltersLoaded) {
-            mFilterSpinner.setSetSelectionListener(null);
-            if (mFilter != null && mFilters != null) {
-                int size = mFilters.size();
-                for (int i = 0; i < size; i++) {
-                    if (mFilters.valueAt(i).equals(mFilter)) {
-                        mFilterSpinner.setSelection(i);
-                        break;
-                    }
-                }
-            }
-            mFilterSpinner.setSetSelectionListener(this);
+            mFilterView.setContactListFilter(mFilter);
+            mFilterView.bindView(false);
         }
     }
 
-    private class FilterSpinnerAdapter extends BaseAdapter {
+    private class FilterListAdapter extends BaseAdapter {
         private LayoutInflater mLayoutInflater;
 
-        public FilterSpinnerAdapter() {
+        public FilterListAdapter() {
             mLayoutInflater = LayoutInflater.from(mContext);
         }
 
@@ -295,31 +309,16 @@
             return mFilters.valueAt(position);
         }
 
-        @Override
-        public View getDropDownView(int position, View convertView, ViewGroup parent) {
-            return getView(position, convertView, parent, true);
-        }
-
-        @Override
         public View getView(int position, View convertView, ViewGroup parent) {
-            return getView(position, convertView, parent, false);
-        }
-
-        public View getView(int position, View convertView, ViewGroup parent, boolean dropdown) {
-            FilterSpinnerItemView view;
-            if (dropdown) {
-                if (convertView != null) {
-                    view = (FilterSpinnerItemView) convertView;
-                } else {
-                    view = (FilterSpinnerItemView) mLayoutInflater.inflate(
-                            R.layout.filter_spinner_item, parent, false);
-                }
+            ContactListFilterView view;
+            if (convertView != null) {
+                view = (ContactListFilterView) convertView;
             } else {
-                view = (FilterSpinnerItemView) mLayoutInflater.inflate(
-                        R.layout.filter_spinner, parent, false);
+                view = (ContactListFilterView) mLayoutInflater.inflate(
+                        R.layout.filter_spinner_item, parent, false);
             }
             view.setContactListFilter(mFilters.valueAt(position));
-            view.bindView(dropdown);
+            view.bindView(true);
             return view;
         }
     }
diff --git a/src/com/android/contacts/list/FilterSpinnerItemView.java b/src/com/android/contacts/list/ContactListFilterView.java
similarity index 94%
rename from src/com/android/contacts/list/FilterSpinnerItemView.java
rename to src/com/android/contacts/list/ContactListFilterView.java
index 32a9ad0..8d0bf3b 100644
--- a/src/com/android/contacts/list/FilterSpinnerItemView.java
+++ b/src/com/android/contacts/list/ContactListFilterView.java
@@ -28,18 +28,18 @@
 /**
  * Contact list filter parameters.
  */
-public final class FilterSpinnerItemView extends LinearLayout {
+public class ContactListFilterView extends LinearLayout {
 
     private ImageView mIcon;
     private TextView mLabel;
     private TextView mIndentedLabel;
     private ContactListFilter mFilter;
 
-    public FilterSpinnerItemView(Context context) {
+    public ContactListFilterView(Context context) {
         super(context);
     }
 
-    public FilterSpinnerItemView(Context context, AttributeSet attrs) {
+    public ContactListFilterView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index ca93e0c..4028a7e 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -303,7 +303,7 @@
 
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (requestCode == REQUEST_CODE_CUSTOMIZE_FILTER && resultCode == Activity.RESULT_OK) {
+        if (requestCode == REQUEST_CODE_CUSTOMIZE_FILTER) {
             mFilterController.selectCustomFilter();
         }
     }