1b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan/*
2b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * Copyright (C) 2013 The Android Open Source Project
3b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan *
4b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * Licensed under the Apache License, Version 2.0 (the "License");
5b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * you may not use this file except in compliance with the License.
6b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * You may obtain a copy of the License at
7b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan *
8b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan *      http://www.apache.org/licenses/LICENSE-2.0
9b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan *
10b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * Unless required by applicable law or agreed to in writing, software
11b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * distributed under the License is distributed on an "AS IS" BASIS,
12b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * See the License for the specific language governing permissions and
14b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * limitations under the License.
15b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan */
16b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
17b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanpackage com.android.timezonepicker;
18b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
19b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.content.Context;
20b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.text.TextUtils;
21b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.util.Log;
22b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.view.LayoutInflater;
23b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.view.View;
24b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.view.View.OnClickListener;
25b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.view.ViewGroup;
26b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.widget.BaseAdapter;
27b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.widget.Filter;
28b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.widget.Filterable;
29b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.widget.TextView;
30b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
31b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.util.ArrayList;
3209a2165919cb9b67c95b7885357c78e20bf5d9fbSam Blitzsteinimport java.util.Collections;
33b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
34b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanpublic class TimeZoneFilterTypeAdapter extends BaseAdapter implements Filterable, OnClickListener {
35b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public static final String TAG = "TimeZoneFilterTypeAdapter";
36b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
37a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    private static final boolean DEBUG = false;
38a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
39b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public static final int FILTER_TYPE_EMPTY = -1;
40b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public static final int FILTER_TYPE_NONE = 0;
41852a8427f0ba0790fa2b7fd1bddba374f03953c6James Kung    public static final int FILTER_TYPE_COUNTRY = 1;
42852a8427f0ba0790fa2b7fd1bddba374f03953c6James Kung    public static final int FILTER_TYPE_STATE = 2;
43852a8427f0ba0790fa2b7fd1bddba374f03953c6James Kung    public static final int FILTER_TYPE_GMT = 3;
44b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
45b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public interface OnSetFilterListener {
46b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        void onSetFilter(int filterType, String str, int time);
47b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
48b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
49b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    static class ViewHolder {
50b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int filterType;
51b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        String str;
52b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int time;
53b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        TextView strTextView;
54b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
55b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        static void setupViewHolder(View v) {
56b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            ViewHolder vh = new ViewHolder();
57b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            vh.strTextView = (TextView) v.findViewById(R.id.value);
58b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            v.setTag(vh);
59b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
60b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
61b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
62b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    class FilterTypeResult {
63b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int type;
64b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        String constraint;
65b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        public int time;
66b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
67852a8427f0ba0790fa2b7fd1bddba374f03953c6James Kung        public FilterTypeResult(int type, String constraint, int time) {
680717b65fee21de6a321e42c9f3852f8b622c3215Michael Chan            this.type = type;
690717b65fee21de6a321e42c9f3852f8b622c3215Michael Chan            this.constraint = constraint;
700717b65fee21de6a321e42c9f3852f8b622c3215Michael Chan            this.time = time;
710717b65fee21de6a321e42c9f3852f8b622c3215Michael Chan        }
720717b65fee21de6a321e42c9f3852f8b622c3215Michael Chan
73b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        @Override
74b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        public String toString() {
75b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            return constraint;
76b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
77b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
78b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
79b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private ArrayList<FilterTypeResult> mLiveResults = new ArrayList<FilterTypeResult>();
80b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private int mLiveResultsCount = 0;
81b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
82b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private ArrayFilter mFilter;
83b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
84b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private LayoutInflater mInflater;
85b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
86b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private TimeZoneData mTimeZoneData;
87b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private OnSetFilterListener mListener;
88b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
89b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public TimeZoneFilterTypeAdapter(Context context, TimeZoneData tzd, OnSetFilterListener l) {
90b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mTimeZoneData = tzd;
91b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mListener = l;
92b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
93b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
94b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
95b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
96b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public int getCount() {
97b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return mLiveResultsCount;
98b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
99b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
100b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
101b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public FilterTypeResult getItem(int position) {
102b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return mLiveResults.get(position);
103b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
104b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
105b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
106b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public long getItemId(int position) {
107b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return position;
108b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
109b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
110b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
111b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public View getView(int position, View convertView, ViewGroup parent) {
112b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        View v;
113b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
114b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (convertView != null) {
115b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            v = convertView;
116b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        } else {
117b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            v = mInflater.inflate(R.layout.time_zone_filter_item, null);
118b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            ViewHolder.setupViewHolder(v);
119b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
120b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
121b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        ViewHolder vh = (ViewHolder) v.getTag();
122b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
123b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (position >= mLiveResults.size()) {
124b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            Log.e(TAG, "getView: " + position + " of " + mLiveResults.size());
125b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
126b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
127b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        FilterTypeResult filter = mLiveResults.get(position);
128b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
129b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        vh.filterType = filter.type;
130b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        vh.str = filter.constraint;
131b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        vh.time = filter.time;
132b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        vh.strTextView.setText(filter.constraint);
133b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return v;
134b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
135b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
136b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    OnClickListener mDummyListener = new OnClickListener() {
137b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
138b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        @Override
139b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        public void onClick(View v) {
140b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
141b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    };
142b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
143b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    // Implements OnClickListener
144b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
145b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    // This onClickListener is actually called from the AutoCompleteTextView's
146b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    // onItemClickListener. Trying to update the text in AutoCompleteTextView
147b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    // is causing an infinite loop.
148b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
149b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public void onClick(View v) {
150b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (mListener != null && v != null) {
151b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            ViewHolder vh = (ViewHolder) v.getTag();
152b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mListener.onSetFilter(vh.filterType, vh.str, vh.time);
153b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
154b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        notifyDataSetInvalidated();
155b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
156b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
157b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    // Implements Filterable
158b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
159b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public Filter getFilter() {
160b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (mFilter == null) {
161b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mFilter = new ArrayFilter();
162b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
163b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return mFilter;
164b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
165b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
166b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private class ArrayFilter extends Filter {
167b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        @Override
168b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        protected FilterResults performFiltering(CharSequence prefix) {
169a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung            if (DEBUG) {
170a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung                Log.d(TAG, "performFiltering >>>> [" + prefix + "]");
171a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung            }
172b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
173b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            FilterResults results = new FilterResults();
174b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            String prefixString = null;
175b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (prefix != null) {
176b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                prefixString = prefix.toString().trim().toLowerCase();
177b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
178b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
179b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (TextUtils.isEmpty(prefixString)) {
180b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                results.values = null;
181b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                results.count = 0;
182b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                return results;
183b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
184b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
185b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // TODO Perf - we can loop through the filtered list if the new
186b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // search string starts with the old search string
187b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            ArrayList<FilterTypeResult> filtered = new ArrayList<FilterTypeResult>();
188b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
189b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // ////////////////////////////////////////
190b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // Search by local time and GMT offset
191b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // ////////////////////////////////////////
192b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            boolean gmtOnly = false;
193b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            int startParsePosition = 0;
194b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (prefixString.charAt(0) == '+' || prefixString.charAt(0) == '-') {
195b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                gmtOnly = true;
196b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
197b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
198b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (prefixString.startsWith("gmt")) {
199b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                startParsePosition = 3;
200b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                gmtOnly = true;
201b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
202b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
203b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            int num = parseNum(prefixString, startParsePosition);
204b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (num != Integer.MIN_VALUE) {
205b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                boolean positiveOnly = prefixString.length() > startParsePosition
206b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        && prefixString.charAt(startParsePosition) == '+';
207b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                handleSearchByGmt(filtered, num, positiveOnly);
208b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
209b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
210b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // ////////////////////////////////////////
211b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // Search by country
212b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // ////////////////////////////////////////
21309a2165919cb9b67c95b7885357c78e20bf5d9fbSam Blitzstein            ArrayList<String> countries = new ArrayList<String>();
214b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            for (String country : mTimeZoneData.mTimeZonesByCountry.keySet()) {
215b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                // TODO Perf - cache toLowerCase()?
2163d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                if (!TextUtils.isEmpty(country)) {
2173d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                    final String lowerCaseCountry = country.toLowerCase();
218020b0c4329f432946df13a43a2831be0ee3b32cdSam Blitzstein                    boolean isMatch = false;
2193d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                    if (lowerCaseCountry.startsWith(prefixString)
2203d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                            || (lowerCaseCountry.charAt(0) == prefixString.charAt(0) &&
2213d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                            isStartingInitialsFor(prefixString, lowerCaseCountry))) {
222020b0c4329f432946df13a43a2831be0ee3b32cdSam Blitzstein                        isMatch = true;
223020b0c4329f432946df13a43a2831be0ee3b32cdSam Blitzstein                    } else if (lowerCaseCountry.contains(" ")){
224020b0c4329f432946df13a43a2831be0ee3b32cdSam Blitzstein                        // We should also search other words in the country name, so that
225020b0c4329f432946df13a43a2831be0ee3b32cdSam Blitzstein                        // searches like "Korea" yield "South Korea".
226020b0c4329f432946df13a43a2831be0ee3b32cdSam Blitzstein                        for (String word : lowerCaseCountry.split(" ")) {
227020b0c4329f432946df13a43a2831be0ee3b32cdSam Blitzstein                            if (word.startsWith(prefixString)) {
228020b0c4329f432946df13a43a2831be0ee3b32cdSam Blitzstein                                isMatch = true;
229020b0c4329f432946df13a43a2831be0ee3b32cdSam Blitzstein                                break;
230020b0c4329f432946df13a43a2831be0ee3b32cdSam Blitzstein                            }
231020b0c4329f432946df13a43a2831be0ee3b32cdSam Blitzstein                        }
232020b0c4329f432946df13a43a2831be0ee3b32cdSam Blitzstein                    }
233020b0c4329f432946df13a43a2831be0ee3b32cdSam Blitzstein                    if (isMatch) {
23409a2165919cb9b67c95b7885357c78e20bf5d9fbSam Blitzstein                        countries.add(country);
235b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
236b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
237b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
23809a2165919cb9b67c95b7885357c78e20bf5d9fbSam Blitzstein            if (countries.size() > 0) {
23909a2165919cb9b67c95b7885357c78e20bf5d9fbSam Blitzstein                // Sort countries alphabetically.
24009a2165919cb9b67c95b7885357c78e20bf5d9fbSam Blitzstein                Collections.sort(countries);
24109a2165919cb9b67c95b7885357c78e20bf5d9fbSam Blitzstein                for (String country : countries) {
24209a2165919cb9b67c95b7885357c78e20bf5d9fbSam Blitzstein                    filtered.add(new FilterTypeResult(FILTER_TYPE_COUNTRY, country, 0));
24309a2165919cb9b67c95b7885357c78e20bf5d9fbSam Blitzstein                }
24409a2165919cb9b67c95b7885357c78e20bf5d9fbSam Blitzstein            }
245b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
246b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // ////////////////////////////////////////
247b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // TODO Search by state
248b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // ////////////////////////////////////////
249a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung            if (DEBUG) {
250a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung                Log.d(TAG, "performFiltering <<<< " + filtered.size() + "[" + prefix + "]");
251a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung            }
252b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
253b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            results.values = filtered;
254b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            results.count = filtered.size();
255b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            return results;
256b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
257b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
2580717b65fee21de6a321e42c9f3852f8b622c3215Michael Chan        /**
2593d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan         * Returns true if the prefixString is an initial for string. Note that
2603d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan         * this method will return true even if prefixString does not cover all
2613d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan         * the words. Words are separated by non-letters which includes spaces
2623d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan         * and symbols).
2633d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan         *
2643d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan         * For example:
26596e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein         * isStartingInitialsFor("UA", "United Arab Emirates") would return true
2663d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan         * isStartingInitialsFor("US", "U.S. Virgin Island") would return true
26796e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein         *
2683d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan         * @param prefixString
2693d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan         * @param string
2703d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan         * @return
2713d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan         */
2723d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan        private boolean isStartingInitialsFor(String prefixString, String string) {
2733d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            final int initialLen = prefixString.length();
2743d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            final int strLen = string.length();
2753d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan
2763d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            int initialIdx = 0;
2773d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            boolean wasWordBreak = true;
2783d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            for (int i = 0; i < strLen; i++) {
2793d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                if (!Character.isLetter(string.charAt(i))) {
2803d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                    wasWordBreak = true;
2813d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                    continue;
2823d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                }
2833d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan
2843d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                if (wasWordBreak) {
2853d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                    if (prefixString.charAt(initialIdx++) != string.charAt(i)) {
2863d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                        return false;
2873d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                    }
2883d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                    if (initialIdx == initialLen) {
2893d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                        return true;
2903d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                    }
2913d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                    wasWordBreak = false;
2923d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                }
2933d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            }
29496e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein
29596e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein            // Special case for "USA". Note that both strings have been turned to lowercase already.
29696e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein            if (prefixString.equals("usa") && string.equals("united states")) {
29796e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein                return true;
29896e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein            }
2993d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            return false;
3003d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan        }
3013d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan
302b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        private void handleSearchByGmt(ArrayList<FilterTypeResult> filtered, int num,
303b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                boolean positiveOnly) {
304b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
305852a8427f0ba0790fa2b7fd1bddba374f03953c6James Kung            FilterTypeResult r;
306b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (num >= 0) {
307b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (num == 1) {
308b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    for (int i = 19; i >= 10; i--) {
309b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        if (mTimeZoneData.hasTimeZonesInHrOffset(i)) {
310852a8427f0ba0790fa2b7fd1bddba374f03953c6James Kung                            r = new FilterTypeResult(FILTER_TYPE_GMT, "GMT+" + i, i);
311b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                            filtered.add(r);
312b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        }
313b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
314b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
315b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
316b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (mTimeZoneData.hasTimeZonesInHrOffset(num)) {
317852a8427f0ba0790fa2b7fd1bddba374f03953c6James Kung                    r = new FilterTypeResult(FILTER_TYPE_GMT, "GMT+" + num, num);
318b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    filtered.add(r);
319b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
320b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                num *= -1;
321b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
322b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
323b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (!positiveOnly && num != 0) {
324b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (mTimeZoneData.hasTimeZonesInHrOffset(num)) {
325852a8427f0ba0790fa2b7fd1bddba374f03953c6James Kung                    r = new FilterTypeResult(FILTER_TYPE_GMT, "GMT" + num, num);
326b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    filtered.add(r);
327b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
328b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
329b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (num == -1) {
330b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    for (int i = -10; i >= -19; i--) {
331b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        if (mTimeZoneData.hasTimeZonesInHrOffset(i)) {
332852a8427f0ba0790fa2b7fd1bddba374f03953c6James Kung                            r = new FilterTypeResult(FILTER_TYPE_GMT, "GMT" + i, i);
333b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                            filtered.add(r);
334b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        }
335b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
336b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
337b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
338b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
339b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
340b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        /**
341b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan         * Acceptable strings are in the following format: [+-]?[0-9]?[0-9]
342b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan         *
343b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan         * @param str
344b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan         * @param startIndex
345b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan         * @return Integer.MIN_VALUE as invalid
346b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan         */
347b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        public int parseNum(String str, int startIndex) {
348b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            int idx = startIndex;
349b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            int num = Integer.MIN_VALUE;
350b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            int negativeMultiplier = 1;
351b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
352b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // First char - check for + and -
353b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            char ch = str.charAt(idx++);
354b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            switch (ch) {
355b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                case '-':
356b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    negativeMultiplier = -1;
357b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // fall through
358b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                case '+':
359b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    if (idx >= str.length()) {
360b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        // No more digits
361b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        return Integer.MIN_VALUE;
362b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
363b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
364b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    ch = str.charAt(idx++);
365b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    break;
366b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
367b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
368b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (!Character.isDigit(ch)) {
369b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                // No digit
370b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                return Integer.MIN_VALUE;
371b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
372b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
373b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // Got first digit
374b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            num = Character.digit(ch, 10);
375b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
376b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // Check next char
377b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (idx < str.length()) {
378b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                ch = str.charAt(idx++);
379b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (Character.isDigit(ch)) {
380b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // Got second digit
381b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    num = 10 * num + Character.digit(ch, 10);
382b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                } else {
383b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    return Integer.MIN_VALUE;
384b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
385b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
386b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
387b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (idx != str.length()) {
388b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                // Invalid
389b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                return Integer.MIN_VALUE;
390b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
391b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
392a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung            if (DEBUG) {
393a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung                Log.d(TAG, "Parsing " + str + " -> " + negativeMultiplier * num);
394a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung            }
395b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            return negativeMultiplier * num;
396b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
397b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
398b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        @SuppressWarnings("unchecked")
399b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        @Override
400b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        protected void publishResults(CharSequence constraint, FilterResults
401b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                results) {
402b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (results.values == null || results.count == 0) {
403b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (mListener != null) {
404b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    int filterType;
405b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    if (TextUtils.isEmpty(constraint)) {
406b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        filterType = FILTER_TYPE_NONE;
407b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    } else {
408b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        filterType = FILTER_TYPE_EMPTY;
409b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
410b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    mListener.onSetFilter(filterType, null, 0);
411b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
412a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung                if (DEBUG) {
413a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung                    Log.d(TAG, "publishResults: " + results.count + " of null [" + constraint);
414a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung                }
415b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            } else {
416b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                mLiveResults = (ArrayList<FilterTypeResult>) results.values;
417a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung                if (DEBUG) {
418a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung                    Log.d(TAG, "publishResults: " + results.count + " of " + mLiveResults.size()
419a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung                            + " [" + constraint);
420a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung                }
421b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
422b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mLiveResultsCount = results.count;
423b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
424b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (results.count > 0) {
425b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                notifyDataSetChanged();
426b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            } else {
427b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                notifyDataSetInvalidated();
428b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
429b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
430b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
431b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan}
432