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