1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/prompts/PromptInput.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,394 @@ 1.4 +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +package org.mozilla.gecko.prompts; 1.10 + 1.11 +import java.text.SimpleDateFormat; 1.12 +import java.util.Calendar; 1.13 +import java.util.GregorianCalendar; 1.14 + 1.15 +import org.json.JSONObject; 1.16 +import org.mozilla.gecko.widget.AllCapsTextView; 1.17 +import org.mozilla.gecko.widget.DateTimePicker; 1.18 + 1.19 +import android.content.Context; 1.20 +import android.content.res.Configuration; 1.21 +import android.os.Build; 1.22 +import android.text.Html; 1.23 +import android.text.InputType; 1.24 +import android.text.TextUtils; 1.25 +import android.text.format.DateFormat; 1.26 +import android.util.Log; 1.27 +import android.view.View; 1.28 +import android.view.ViewGroup.LayoutParams; 1.29 +import android.view.inputmethod.InputMethodManager; 1.30 +import android.widget.ArrayAdapter; 1.31 +import android.widget.CheckBox; 1.32 +import android.widget.DatePicker; 1.33 +import android.widget.EditText; 1.34 +import android.widget.LinearLayout; 1.35 +import android.widget.Spinner; 1.36 +import android.widget.TextView; 1.37 +import android.widget.TimePicker; 1.38 + 1.39 +public class PromptInput { 1.40 + protected final String mLabel; 1.41 + protected final String mType; 1.42 + protected final String mId; 1.43 + protected final String mValue; 1.44 + protected OnChangeListener mListener; 1.45 + protected View mView; 1.46 + public static final String LOGTAG = "GeckoPromptInput"; 1.47 + 1.48 + public interface OnChangeListener { 1.49 + public void onChange(PromptInput input); 1.50 + } 1.51 + 1.52 + public void setListener(OnChangeListener listener) { 1.53 + mListener = listener; 1.54 + } 1.55 + 1.56 + public static class EditInput extends PromptInput { 1.57 + protected final String mHint; 1.58 + protected final boolean mAutofocus; 1.59 + public static final String INPUT_TYPE = "textbox"; 1.60 + 1.61 + public EditInput(JSONObject object) { 1.62 + super(object); 1.63 + mHint = object.optString("hint"); 1.64 + mAutofocus = object.optBoolean("autofocus"); 1.65 + } 1.66 + 1.67 + public View getView(final Context context) throws UnsupportedOperationException { 1.68 + EditText input = new EditText(context); 1.69 + input.setInputType(InputType.TYPE_CLASS_TEXT); 1.70 + input.setText(mValue); 1.71 + 1.72 + if (!TextUtils.isEmpty(mHint)) { 1.73 + input.setHint(mHint); 1.74 + } 1.75 + 1.76 + if (mAutofocus) { 1.77 + input.setOnFocusChangeListener(new View.OnFocusChangeListener() { 1.78 + @Override 1.79 + public void onFocusChange(View v, boolean hasFocus) { 1.80 + if (hasFocus) { 1.81 + ((InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE)).showSoftInput(v, 0); 1.82 + } 1.83 + } 1.84 + }); 1.85 + input.requestFocus(); 1.86 + } 1.87 + 1.88 + mView = (View)input; 1.89 + return mView; 1.90 + } 1.91 + 1.92 + @Override 1.93 + public Object getValue() { 1.94 + EditText edit = (EditText)mView; 1.95 + return edit.getText(); 1.96 + } 1.97 + } 1.98 + 1.99 + public static class NumberInput extends EditInput { 1.100 + public static final String INPUT_TYPE = "number"; 1.101 + public NumberInput(JSONObject obj) { 1.102 + super(obj); 1.103 + } 1.104 + 1.105 + public View getView(final Context context) throws UnsupportedOperationException { 1.106 + EditText input = (EditText) super.getView(context); 1.107 + input.setRawInputType(Configuration.KEYBOARD_12KEY); 1.108 + input.setInputType(InputType.TYPE_CLASS_NUMBER | 1.109 + InputType.TYPE_NUMBER_FLAG_SIGNED); 1.110 + return input; 1.111 + } 1.112 + } 1.113 + 1.114 + public static class PasswordInput extends EditInput { 1.115 + public static final String INPUT_TYPE = "password"; 1.116 + public PasswordInput(JSONObject obj) { 1.117 + super(obj); 1.118 + } 1.119 + 1.120 + public View getView(Context context) throws UnsupportedOperationException { 1.121 + EditText input = (EditText) super.getView(context); 1.122 + input.setInputType(InputType.TYPE_CLASS_TEXT | 1.123 + InputType.TYPE_TEXT_VARIATION_PASSWORD | 1.124 + InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); 1.125 + return input; 1.126 + } 1.127 + 1.128 + @Override 1.129 + public Object getValue() { 1.130 + EditText edit = (EditText)mView; 1.131 + return edit.getText(); 1.132 + } 1.133 + } 1.134 + 1.135 + public static class CheckboxInput extends PromptInput { 1.136 + public static final String INPUT_TYPE = "checkbox"; 1.137 + private boolean mChecked; 1.138 + 1.139 + public CheckboxInput(JSONObject obj) { 1.140 + super(obj); 1.141 + mChecked = obj.optBoolean("checked"); 1.142 + } 1.143 + 1.144 + public View getView(Context context) throws UnsupportedOperationException { 1.145 + CheckBox checkbox = new CheckBox(context); 1.146 + checkbox.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); 1.147 + checkbox.setText(mLabel); 1.148 + checkbox.setChecked(mChecked); 1.149 + mView = (View)checkbox; 1.150 + return mView; 1.151 + } 1.152 + 1.153 + @Override 1.154 + public Object getValue() { 1.155 + CheckBox checkbox = (CheckBox)mView; 1.156 + return checkbox.isChecked() ? Boolean.TRUE : Boolean.FALSE; 1.157 + } 1.158 + } 1.159 + 1.160 + public static class DateTimeInput extends PromptInput { 1.161 + public static final String[] INPUT_TYPES = new String[] { 1.162 + "date", 1.163 + "week", 1.164 + "time", 1.165 + "datetime-local", 1.166 + "datetime", 1.167 + "month" 1.168 + }; 1.169 + 1.170 + public DateTimeInput(JSONObject obj) { 1.171 + super(obj); 1.172 + } 1.173 + 1.174 + public View getView(Context context) throws UnsupportedOperationException { 1.175 + if (mType.equals("date")) { 1.176 + try { 1.177 + DateTimePicker input = new DateTimePicker(context, "yyyy-MM-dd", mValue, 1.178 + DateTimePicker.PickersState.DATE); 1.179 + input.toggleCalendar(true); 1.180 + mView = (View)input; 1.181 + } catch (UnsupportedOperationException ex) { 1.182 + // We can't use our custom version of the DatePicker widget because the sdk is too old. 1.183 + // But we can fallback on the native one. 1.184 + DatePicker input = new DatePicker(context); 1.185 + try { 1.186 + if (!TextUtils.isEmpty(mValue)) { 1.187 + GregorianCalendar calendar = new GregorianCalendar(); 1.188 + calendar.setTime(new SimpleDateFormat("yyyy-MM-dd").parse(mValue)); 1.189 + input.updateDate(calendar.get(Calendar.YEAR), 1.190 + calendar.get(Calendar.MONTH), 1.191 + calendar.get(Calendar.DAY_OF_MONTH)); 1.192 + } 1.193 + } catch (Exception e) { 1.194 + Log.e(LOGTAG, "error parsing format string: " + e); 1.195 + } 1.196 + mView = (View)input; 1.197 + } 1.198 + } else if (mType.equals("week")) { 1.199 + DateTimePicker input = new DateTimePicker(context, "yyyy-'W'ww", mValue, 1.200 + DateTimePicker.PickersState.WEEK); 1.201 + mView = (View)input; 1.202 + } else if (mType.equals("time")) { 1.203 + TimePicker input = new TimePicker(context); 1.204 + input.setIs24HourView(DateFormat.is24HourFormat(context)); 1.205 + 1.206 + GregorianCalendar calendar = new GregorianCalendar(); 1.207 + if (!TextUtils.isEmpty(mValue)) { 1.208 + try { 1.209 + calendar.setTime(new SimpleDateFormat("HH:mm").parse(mValue)); 1.210 + } catch (Exception e) { } 1.211 + } 1.212 + input.setCurrentHour(calendar.get(GregorianCalendar.HOUR_OF_DAY)); 1.213 + input.setCurrentMinute(calendar.get(GregorianCalendar.MINUTE)); 1.214 + mView = (View)input; 1.215 + } else if (mType.equals("datetime-local") || mType.equals("datetime")) { 1.216 + DateTimePicker input = new DateTimePicker(context, "yyyy-MM-dd HH:mm", mValue, 1.217 + DateTimePicker.PickersState.DATETIME); 1.218 + input.toggleCalendar(true); 1.219 + mView = (View)input; 1.220 + } else if (mType.equals("month")) { 1.221 + DateTimePicker input = new DateTimePicker(context, "yyyy-MM", mValue, 1.222 + DateTimePicker.PickersState.MONTH); 1.223 + mView = (View)input; 1.224 + } 1.225 + return mView; 1.226 + } 1.227 + 1.228 + private static String formatDateString(String dateFormat, Calendar calendar) { 1.229 + return new SimpleDateFormat(dateFormat).format(calendar.getTime()); 1.230 + } 1.231 + 1.232 + @Override 1.233 + public Object getValue() { 1.234 + if (Build.VERSION.SDK_INT < 11 && mType.equals("date")) { 1.235 + // We can't use the custom DateTimePicker with a sdk older than 11. 1.236 + // Fallback on the native DatePicker. 1.237 + DatePicker dp = (DatePicker)mView; 1.238 + GregorianCalendar calendar = 1.239 + new GregorianCalendar(dp.getYear(),dp.getMonth(),dp.getDayOfMonth()); 1.240 + return formatDateString("yyyy-MM-dd",calendar); 1.241 + } else if (mType.equals("time")) { 1.242 + TimePicker tp = (TimePicker)mView; 1.243 + GregorianCalendar calendar = 1.244 + new GregorianCalendar(0,0,0,tp.getCurrentHour(),tp.getCurrentMinute()); 1.245 + return formatDateString("HH:mm",calendar); 1.246 + } else { 1.247 + DateTimePicker dp = (DateTimePicker)mView; 1.248 + GregorianCalendar calendar = new GregorianCalendar(); 1.249 + calendar.setTimeInMillis(dp.getTimeInMillis()); 1.250 + if (mType.equals("date")) { 1.251 + return formatDateString("yyyy-MM-dd",calendar); 1.252 + } else if (mType.equals("week")) { 1.253 + return formatDateString("yyyy-'W'ww",calendar); 1.254 + } else if (mType.equals("datetime-local")) { 1.255 + return formatDateString("yyyy-MM-dd HH:mm",calendar); 1.256 + } else if (mType.equals("datetime")) { 1.257 + calendar.set(GregorianCalendar.ZONE_OFFSET,0); 1.258 + calendar.setTimeInMillis(dp.getTimeInMillis()); 1.259 + return formatDateString("yyyy-MM-dd HH:mm",calendar); 1.260 + } else if (mType.equals("month")) { 1.261 + return formatDateString("yyyy-MM",calendar); 1.262 + } 1.263 + } 1.264 + return super.getValue(); 1.265 + } 1.266 + } 1.267 + 1.268 + public static class MenulistInput extends PromptInput { 1.269 + public static final String INPUT_TYPE = "menulist"; 1.270 + private static String[] mListitems; 1.271 + private static int mSelected; 1.272 + 1.273 + public Spinner spinner; 1.274 + public AllCapsTextView textView; 1.275 + 1.276 + public MenulistInput(JSONObject obj) { 1.277 + super(obj); 1.278 + mListitems = Prompt.getStringArray(obj, "values"); 1.279 + mSelected = obj.optInt("selected"); 1.280 + } 1.281 + 1.282 + public View getView(final Context context) throws UnsupportedOperationException { 1.283 + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { 1.284 + spinner = new Spinner(context); 1.285 + } else { 1.286 + spinner = new Spinner(context, Spinner.MODE_DIALOG); 1.287 + } 1.288 + try { 1.289 + if (mListitems.length > 0) { 1.290 + ArrayAdapter<String> adapter = new ArrayAdapter<String>(context, android.R.layout.simple_spinner_item, mListitems); 1.291 + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 1.292 + 1.293 + spinner.setAdapter(adapter); 1.294 + spinner.setSelection(mSelected); 1.295 + } 1.296 + } catch(Exception ex) { } 1.297 + 1.298 + if (!TextUtils.isEmpty(mLabel)) { 1.299 + LinearLayout container = new LinearLayout(context); 1.300 + container.setOrientation(LinearLayout.VERTICAL); 1.301 + 1.302 + textView = new AllCapsTextView(context, null); 1.303 + textView.setText(mLabel); 1.304 + container.addView(textView); 1.305 + 1.306 + container.addView(spinner); 1.307 + return container; 1.308 + } 1.309 + 1.310 + return spinner; 1.311 + } 1.312 + 1.313 + @Override 1.314 + public Object getValue() { 1.315 + return new Integer(spinner.getSelectedItemPosition()); 1.316 + } 1.317 + } 1.318 + 1.319 + public static class LabelInput extends PromptInput { 1.320 + public static final String INPUT_TYPE = "label"; 1.321 + public LabelInput(JSONObject obj) { 1.322 + super(obj); 1.323 + } 1.324 + 1.325 + public View getView(Context context) throws UnsupportedOperationException { 1.326 + // not really an input, but a way to add labels and such to the dialog 1.327 + TextView view = new TextView(context); 1.328 + view.setText(Html.fromHtml(mLabel)); 1.329 + mView = view; 1.330 + return mView; 1.331 + } 1.332 + } 1.333 + 1.334 + public PromptInput(JSONObject obj) { 1.335 + mLabel = obj.optString("label"); 1.336 + mType = obj.optString("type"); 1.337 + String id = obj.optString("id"); 1.338 + mId = TextUtils.isEmpty(id) ? mType : id; 1.339 + mValue = obj.optString("value"); 1.340 + } 1.341 + 1.342 + public static PromptInput getInput(JSONObject obj) { 1.343 + String type = obj.optString("type"); 1.344 + if (EditInput.INPUT_TYPE.equals(type)) { 1.345 + return new EditInput(obj); 1.346 + } else if (NumberInput.INPUT_TYPE.equals(type)) { 1.347 + return new NumberInput(obj); 1.348 + } else if (PasswordInput.INPUT_TYPE.equals(type)) { 1.349 + return new PasswordInput(obj); 1.350 + } else if (CheckboxInput.INPUT_TYPE.equals(type)) { 1.351 + return new CheckboxInput(obj); 1.352 + } else if (MenulistInput.INPUT_TYPE.equals(type)) { 1.353 + return new MenulistInput(obj); 1.354 + } else if (LabelInput.INPUT_TYPE.equals(type)) { 1.355 + return new LabelInput(obj); 1.356 + } else if (IconGridInput.INPUT_TYPE.equals(type)) { 1.357 + return new IconGridInput(obj); 1.358 + } else if (ColorPickerInput.INPUT_TYPE.equals(type)) { 1.359 + return new ColorPickerInput(obj); 1.360 + } else if (TabInput.INPUT_TYPE.equals(type)) { 1.361 + return new TabInput(obj); 1.362 + } else { 1.363 + for (String dtType : DateTimeInput.INPUT_TYPES) { 1.364 + if (dtType.equals(type)) { 1.365 + return new DateTimeInput(obj); 1.366 + } 1.367 + } 1.368 + } 1.369 + return null; 1.370 + } 1.371 + 1.372 + public View getView(Context context) throws UnsupportedOperationException { 1.373 + return null; 1.374 + } 1.375 + 1.376 + public String getId() { 1.377 + return mId; 1.378 + } 1.379 + 1.380 + public Object getValue() { 1.381 + return null; 1.382 + } 1.383 + 1.384 + public boolean getScrollable() { 1.385 + return false; 1.386 + } 1.387 + 1.388 + public boolean canApplyInputStyle() { 1.389 + return true; 1.390 + } 1.391 + 1.392 + protected void notifyListeners(String val) { 1.393 + if (mListener != null) { 1.394 + mListener.onChange(this); 1.395 + } 1.396 + } 1.397 +}