TimeZonePickerView.java revision a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7
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;
20dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzsteinimport android.graphics.drawable.Drawable;
21b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.text.Editable;
22dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzsteinimport android.text.Spannable;
23dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzsteinimport android.text.SpannableStringBuilder;
24b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.text.TextWatcher;
25dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzsteinimport android.text.style.ImageSpan;
26b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.util.AttributeSet;
27b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.view.LayoutInflater;
28b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.view.View;
29a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kungimport android.view.View.OnClickListener;
30b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.widget.AdapterView;
31b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.widget.AdapterView.OnItemClickListener;
32b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.widget.AutoCompleteTextView;
33dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzsteinimport android.widget.ImageButton;
34b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.widget.LinearLayout;
35b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.widget.ListView;
36b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
37a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kungpublic class TimeZonePickerView extends LinearLayout implements TextWatcher, OnItemClickListener,
38a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    OnClickListener {
39b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static final String TAG = "TimeZonePickerView";
40b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
41b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private Context mContext;
42b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private AutoCompleteTextView mAutoCompleteTextView;
43b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private TimeZoneFilterTypeAdapter mFilterAdapter;
44a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    private boolean mHideFilterSearchOnStart = false;
45a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    private boolean mFirstTime = true;
46b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    TimeZoneResultAdapter mResultAdapter;
47b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
48dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein    private ImageButton mClearButton;
49dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein
50b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public interface OnTimeZoneSetListener {
51b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        void onTimeZoneSet(TimeZoneInfo tzi);
52b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
53b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
54b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public TimeZonePickerView(Context context, AttributeSet attrs,
55a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung            String timeZone, long timeMillis, OnTimeZoneSetListener l,
56a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung            boolean hideFilterSearch) {
57b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        super(context, attrs);
58b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mContext = context;
59b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        LayoutInflater inflater = (LayoutInflater) context.getSystemService(
60b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                Context.LAYOUT_INFLATER_SERVICE);
61b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        inflater.inflate(R.layout.timezonepickerview, this, true);
62b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
63a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        mHideFilterSearchOnStart = hideFilterSearch;
64a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
65b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        TimeZoneData tzd = new TimeZoneData(mContext, timeZone, timeMillis);
66b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
67b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mResultAdapter = new TimeZoneResultAdapter(mContext, tzd, l);
68b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        ListView timeZoneList = (ListView) findViewById(R.id.timezonelist);
69b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        timeZoneList.setAdapter(mResultAdapter);
70b064db0d1a7ffcedddd691b35d57e2cdb0268883Michael Chan        timeZoneList.setOnItemClickListener(mResultAdapter);
71b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
72b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mFilterAdapter = new TimeZoneFilterTypeAdapter(mContext, tzd, mResultAdapter);
73a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
74a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        mAutoCompleteTextView = (AutoCompleteTextView) findViewById(R.id.searchBox);
75b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mAutoCompleteTextView.addTextChangedListener(this);
76b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mAutoCompleteTextView.setOnItemClickListener(this);
77a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        mAutoCompleteTextView.setOnClickListener(this);
78dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein
79dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein        updateHint(R.string.hint_time_zone_search, R.drawable.ic_search_holo_light);
80dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein        mClearButton = (ImageButton) findViewById(R.id.clear_search);
81dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein        mClearButton.setOnClickListener(new OnClickListener() {
82dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein            @Override
83dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein            public void onClick(View v) {
84dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein                mAutoCompleteTextView.getEditableText().clear();
85dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein            }
86dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein        });
87dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein    }
88dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein
89a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    public void showFilterResults(int type, String string, int time) {
90a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        if (mResultAdapter != null) {
91a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung            mResultAdapter.onSetFilter(type, string, time);
92a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        }
93a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    }
94a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
95a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    public boolean hasResults() {
96a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        return mResultAdapter != null && mResultAdapter.hasResults();
97a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    }
98a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
99a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    public int getLastFilterType() {
100a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        return mResultAdapter != null ? mResultAdapter.getLastFilterType() : -1;
101a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    }
102a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
103a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    public String getLastFilterString() {
104a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        return mResultAdapter != null ? mResultAdapter.getLastFilterString() : null;
105a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    }
106a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
107a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    public int getLastFilterTime() {
108a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        return mResultAdapter != null ? mResultAdapter.getLastFilterType() : -1;
109a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    }
110a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
111a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    public boolean getHideFilterSearchOnStart() {
112a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        return mHideFilterSearchOnStart;
113a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    }
114a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
115dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein    private void updateHint(int hintTextId, int imageDrawableId) {
116dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein        String hintText = getResources().getString(hintTextId);
117dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein        Drawable searchIcon = getResources().getDrawable(imageDrawableId);
118dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein
119dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein        SpannableStringBuilder ssb = new SpannableStringBuilder("   "); // for the icon
120dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein        ssb.append(hintText);
121dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein        int textSize = (int) (mAutoCompleteTextView.getTextSize() * 1.25);
122dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein        searchIcon.setBounds(0, 0, textSize, textSize);
123dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein        ssb.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
124dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein        mAutoCompleteTextView.setHint(ssb);
125b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
126b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
127b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    // Implementation of TextWatcher
128b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
129b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
130b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
131b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
132b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    // Implementation of TextWatcher
133b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
134b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public void onTextChanged(CharSequence s, int start, int before, int count) {
135a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        if (mFirstTime && mHideFilterSearchOnStart) {
136a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung            mFirstTime = false;
137a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung            return;
138a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        }
139a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        filterOnString(s.toString());
140b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
141b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
142b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    // Implementation of TextWatcher
143b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
144b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public void afterTextChanged(Editable s) {
145dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein        if (mClearButton != null) {
146dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein            mClearButton.setVisibility(s.length() > 0 ? View.VISIBLE : View.GONE);
147dba26e2a0025a404fba38a44500c0f072735a610Sam Blitzstein        }
148b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
149b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
150b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
151b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
152b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // An onClickListener for the view item because I haven't figured out a
153b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // way to update the AutoCompleteTextView without causing an infinite loop.
154a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        mHideFilterSearchOnStart = true;
155b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mFilterAdapter.onClick(view);
156b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
157a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
158a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    @Override
159a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    public void onClick(View v) {
160a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        if (mAutoCompleteTextView != null && !mAutoCompleteTextView.isPopupShowing()) {
161a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung            filterOnString(mAutoCompleteTextView.getText().toString());
162a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        }
163a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    }
164a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
165a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    // This method will set the adapter if no adapter has been set.  The adapter is initialized
166a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    // here to prevent the drop-down from appearing uninvited on orientation change, as the
167a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    // AutoCompleteTextView.setText() will trigger the drop-down if the adapter has been set.
168a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    private void filterOnString(String string) {
169a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        if (mAutoCompleteTextView.getAdapter() == null) {
170a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung            mAutoCompleteTextView.setAdapter(mFilterAdapter);
171a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        }
172a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        mHideFilterSearchOnStart = false;
173a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        mFilterAdapter.getFilter().filter(string);
174a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    }
175b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan}
176