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