1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.timezonepicker; 18 19 import android.content.Context; 20 import android.graphics.drawable.Drawable; 21 import android.text.Editable; 22 import android.text.Spannable; 23 import android.text.SpannableStringBuilder; 24 import android.text.TextWatcher; 25 import android.text.style.ImageSpan; 26 import android.util.AttributeSet; 27 import android.view.LayoutInflater; 28 import android.view.View; 29 import android.view.View.OnClickListener; 30 import android.view.inputmethod.InputMethodManager; 31 import android.widget.AdapterView; 32 import android.widget.AdapterView.OnItemClickListener; 33 import android.widget.AutoCompleteTextView; 34 import android.widget.ImageButton; 35 import android.widget.LinearLayout; 36 import android.widget.ListView; 37 38 public class TimeZonePickerView extends LinearLayout implements TextWatcher, OnItemClickListener, 39 OnClickListener { 40 private static final String TAG = "TimeZonePickerView"; 41 42 private Context mContext; 43 private AutoCompleteTextView mAutoCompleteTextView; 44 private TimeZoneFilterTypeAdapter mFilterAdapter; 45 private boolean mHideFilterSearchOnStart = false; 46 private boolean mFirstTime = true; 47 TimeZoneResultAdapter mResultAdapter; 48 49 private ImageButton mClearButton; 50 51 public interface OnTimeZoneSetListener { 52 void onTimeZoneSet(TimeZoneInfo tzi); 53 } 54 55 public TimeZonePickerView(Context context, AttributeSet attrs, 56 String timeZone, long timeMillis, OnTimeZoneSetListener l, 57 boolean hideFilterSearch) { 58 super(context, attrs); 59 mContext = context; 60 LayoutInflater inflater = (LayoutInflater) context.getSystemService( 61 Context.LAYOUT_INFLATER_SERVICE); 62 inflater.inflate(R.layout.timezonepickerview, this, true); 63 64 mHideFilterSearchOnStart = hideFilterSearch; 65 66 TimeZoneData tzd = new TimeZoneData(mContext, timeZone, timeMillis); 67 68 mResultAdapter = new TimeZoneResultAdapter(mContext, tzd, l); 69 ListView timeZoneList = (ListView) findViewById(R.id.timezonelist); 70 timeZoneList.setAdapter(mResultAdapter); 71 timeZoneList.setOnItemClickListener(mResultAdapter); 72 73 mFilterAdapter = new TimeZoneFilterTypeAdapter(mContext, tzd, mResultAdapter); 74 75 mAutoCompleteTextView = (AutoCompleteTextView) findViewById(R.id.searchBox); 76 mAutoCompleteTextView.addTextChangedListener(this); 77 mAutoCompleteTextView.setOnItemClickListener(this); 78 mAutoCompleteTextView.setOnClickListener(this); 79 80 updateHint(R.string.hint_time_zone_search, R.drawable.ic_search_holo_light); 81 mClearButton = (ImageButton) findViewById(R.id.clear_search); 82 mClearButton.setOnClickListener(new OnClickListener() { 83 @Override 84 public void onClick(View v) { 85 mAutoCompleteTextView.getEditableText().clear(); 86 } 87 }); 88 } 89 90 public void showFilterResults(int type, String string, int time) { 91 if (mResultAdapter != null) { 92 mResultAdapter.onSetFilter(type, string, time); 93 } 94 } 95 96 public boolean hasResults() { 97 return mResultAdapter != null && mResultAdapter.hasResults(); 98 } 99 100 public int getLastFilterType() { 101 return mResultAdapter != null ? mResultAdapter.getLastFilterType() : -1; 102 } 103 104 public String getLastFilterString() { 105 return mResultAdapter != null ? mResultAdapter.getLastFilterString() : null; 106 } 107 108 public int getLastFilterTime() { 109 return mResultAdapter != null ? mResultAdapter.getLastFilterType() : -1; 110 } 111 112 public boolean getHideFilterSearchOnStart() { 113 return mHideFilterSearchOnStart; 114 } 115 116 private void updateHint(int hintTextId, int imageDrawableId) { 117 String hintText = getResources().getString(hintTextId); 118 Drawable searchIcon = getResources().getDrawable(imageDrawableId); 119 120 SpannableStringBuilder ssb = new SpannableStringBuilder(" "); // for the icon 121 ssb.append(hintText); 122 int textSize = (int) (mAutoCompleteTextView.getTextSize() * 1.25); 123 searchIcon.setBounds(0, 0, textSize, textSize); 124 ssb.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 125 mAutoCompleteTextView.setHint(ssb); 126 } 127 128 // Implementation of TextWatcher 129 @Override 130 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 131 } 132 133 // Implementation of TextWatcher 134 @Override 135 public void onTextChanged(CharSequence s, int start, int before, int count) { 136 if (mFirstTime && mHideFilterSearchOnStart) { 137 mFirstTime = false; 138 return; 139 } 140 filterOnString(s.toString()); 141 } 142 143 // Implementation of TextWatcher 144 @Override 145 public void afterTextChanged(Editable s) { 146 if (mClearButton != null) { 147 mClearButton.setVisibility(s.length() > 0 ? View.VISIBLE : View.GONE); 148 } 149 } 150 151 @Override 152 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 153 // Hide the keyboard since the user explicitly selected an item. 154 InputMethodManager manager = 155 (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 156 manager.hideSoftInputFromWindow(mAutoCompleteTextView.getWindowToken(), 0); 157 // An onClickListener for the view item because I haven't figured out a 158 // way to update the AutoCompleteTextView without causing an infinite loop. 159 mHideFilterSearchOnStart = true; 160 mFilterAdapter.onClick(view); 161 } 162 163 @Override 164 public void onClick(View v) { 165 if (mAutoCompleteTextView != null && !mAutoCompleteTextView.isPopupShowing()) { 166 filterOnString(mAutoCompleteTextView.getText().toString()); 167 } 168 } 169 170 // This method will set the adapter if no adapter has been set. The adapter is initialized 171 // here to prevent the drop-down from appearing uninvited on orientation change, as the 172 // AutoCompleteTextView.setText() will trigger the drop-down if the adapter has been set. 173 private void filterOnString(String string) { 174 if (mAutoCompleteTextView.getAdapter() == null) { 175 mAutoCompleteTextView.setAdapter(mFilterAdapter); 176 } 177 mHideFilterSearchOnStart = false; 178 mFilterAdapter.getFilter().filter(string); 179 } 180 } 181