1 /* 2 * Copyright (C) 2016 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.googlecode.android_scripting.facade.ui; 18 19 import android.app.Activity; 20 import android.app.AlertDialog; 21 import android.app.AlertDialog.Builder; 22 import android.content.DialogInterface; 23 import android.text.method.PasswordTransformationMethod; 24 import android.widget.EditText; 25 26 import java.util.ArrayList; 27 import java.util.HashMap; 28 import java.util.List; 29 import java.util.Map; 30 import java.util.Set; 31 import java.util.TreeSet; 32 33 import org.json.JSONArray; 34 import org.json.JSONException; 35 36 /** 37 * Wrapper class for alert dialog running in separate thread. 38 * 39 * @author MeanEYE.rcf (meaneye.rcf (at) gmail.com) 40 */ 41 class AlertDialogTask extends DialogTask { 42 43 private final String mTitle; 44 private final String mMessage; 45 46 private final List<String> mItems; 47 private final Set<Integer> mSelectedItems; 48 private final Map<String, Object> mResultMap; 49 private InputType mInputType; 50 private int mEditInputType = 0; 51 52 private String mPositiveButtonText; 53 private String mNegativeButtonText; 54 private String mNeutralButtonText; 55 56 private EditText mEditText; 57 private String mDefaultText; 58 59 private enum InputType { 60 DEFAULT, MENU, SINGLE_CHOICE, MULTI_CHOICE, PLAIN_TEXT, PASSWORD; 61 } 62 63 public AlertDialogTask(String title, String message) { 64 mTitle = title; 65 mMessage = message; 66 mInputType = InputType.DEFAULT; 67 mItems = new ArrayList<String>(); 68 mSelectedItems = new TreeSet<Integer>(); 69 mResultMap = new HashMap<String, Object>(); 70 } 71 72 public void setPositiveButtonText(String text) { 73 mPositiveButtonText = text; 74 } 75 76 public void setNegativeButtonText(String text) { 77 mNegativeButtonText = text; 78 } 79 80 public void setNeutralButtonText(String text) { 81 mNeutralButtonText = text; 82 } 83 84 /** 85 * Set list items. 86 * 87 * @param items 88 */ 89 public void setItems(JSONArray items) { 90 mItems.clear(); 91 for (int i = 0; i < items.length(); i++) { 92 try { 93 mItems.add(items.getString(i)); 94 } catch (JSONException e) { 95 throw new RuntimeException(e); 96 } 97 } 98 mInputType = InputType.MENU; 99 } 100 101 /** 102 * Set single choice items. 103 * 104 * @param items 105 * a list of items as {@link String}s to display 106 * @param selected 107 * the index of the item that is selected by default 108 */ 109 public void setSingleChoiceItems(JSONArray items, int selected) { 110 setItems(items); 111 mSelectedItems.clear(); 112 mSelectedItems.add(selected); 113 mInputType = InputType.SINGLE_CHOICE; 114 } 115 116 /** 117 * Set multi choice items. 118 * 119 * @param items 120 * a list of items as {@link String}s to display 121 * @param selected 122 * a list of indices for items that should be selected by default 123 * @throws JSONException 124 */ 125 public void setMultiChoiceItems(JSONArray items, JSONArray selected) throws JSONException { 126 setItems(items); 127 mSelectedItems.clear(); 128 if (selected != null) { 129 for (int i = 0; i < selected.length(); i++) { 130 mSelectedItems.add(selected.getInt(i)); 131 } 132 } 133 mInputType = InputType.MULTI_CHOICE; 134 } 135 136 /** 137 * Returns the list of selected items. 138 */ 139 public Set<Integer> getSelectedItems() { 140 return mSelectedItems; 141 } 142 143 public void setTextInput(String defaultText) { 144 mDefaultText = defaultText; 145 mInputType = InputType.PLAIN_TEXT; 146 setEditInputType("text"); 147 } 148 149 public void setEditInputType(String editInputType) { 150 String[] list = editInputType.split("\\|"); 151 Map<String, Integer> types = ViewInflater.getInputTypes(); 152 mEditInputType = 0; 153 for (String flag : list) { 154 Integer v = types.get(flag.trim()); 155 if (v != null) { 156 mEditInputType |= v; 157 } 158 } 159 if (mEditInputType == 0) { 160 mEditInputType = android.text.InputType.TYPE_CLASS_TEXT; 161 } 162 } 163 164 public void setPasswordInput() { 165 mInputType = InputType.PASSWORD; 166 } 167 168 @Override 169 public void onCreate() { 170 super.onCreate(); 171 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 172 if (mTitle != null) { 173 builder.setTitle(mTitle); 174 } 175 // Can't display both a message and items. We'll elect to show the items instead. 176 if (mMessage != null && mItems.isEmpty()) { 177 builder.setMessage(mMessage); 178 } 179 switch (mInputType) { 180 // Add single choice menu items to dialog. 181 case SINGLE_CHOICE: 182 builder.setSingleChoiceItems(getItemsAsCharSequenceArray(), mSelectedItems.iterator().next(), 183 new DialogInterface.OnClickListener() { 184 @Override 185 public void onClick(DialogInterface dialog, int item) { 186 mSelectedItems.clear(); 187 mSelectedItems.add(item); 188 } 189 }); 190 break; 191 // Add multiple choice items to the dialog. 192 case MULTI_CHOICE: 193 boolean[] selectedItems = new boolean[mItems.size()]; 194 for (int i : mSelectedItems) { 195 selectedItems[i] = true; 196 } 197 builder.setMultiChoiceItems(getItemsAsCharSequenceArray(), selectedItems, 198 new DialogInterface.OnMultiChoiceClickListener() { 199 @Override 200 public void onClick(DialogInterface dialog, int item, boolean isChecked) { 201 if (isChecked) { 202 mSelectedItems.add(item); 203 } else { 204 mSelectedItems.remove(item); 205 } 206 } 207 }); 208 break; 209 // Add standard, menu-like, items to dialog. 210 case MENU: 211 builder.setItems(getItemsAsCharSequenceArray(), new DialogInterface.OnClickListener() { 212 public void onClick(DialogInterface dialog, int item) { 213 Map<String, Integer> result = new HashMap<String, Integer>(); 214 result.put("item", item); 215 dismissDialog(); 216 setResult(result); 217 } 218 }); 219 break; 220 case PLAIN_TEXT: 221 mEditText = new EditText(getActivity()); 222 if (mDefaultText != null) { 223 mEditText.setText(mDefaultText); 224 } 225 mEditText.setInputType(mEditInputType); 226 builder.setView(mEditText); 227 break; 228 case PASSWORD: 229 mEditText = new EditText(getActivity()); 230 mEditText.setInputType(android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD); 231 mEditText.setTransformationMethod(new PasswordTransformationMethod()); 232 builder.setView(mEditText); 233 break; 234 default: 235 // No input type specified. 236 } 237 configureButtons(builder, getActivity()); 238 addOnCancelListener(builder, getActivity()); 239 mDialog = builder.show(); 240 mShowLatch.countDown(); 241 } 242 243 private CharSequence[] getItemsAsCharSequenceArray() { 244 return mItems.toArray(new CharSequence[mItems.size()]); 245 } 246 247 private Builder addOnCancelListener(final AlertDialog.Builder builder, final Activity activity) { 248 return builder.setOnCancelListener(new DialogInterface.OnCancelListener() { 249 @Override 250 public void onCancel(DialogInterface dialog) { 251 mResultMap.put("canceled", true); 252 setResult(); 253 } 254 }); 255 } 256 257 private void configureButtons(final AlertDialog.Builder builder, final Activity activity) { 258 DialogInterface.OnClickListener buttonListener = new DialogInterface.OnClickListener() { 259 @Override 260 public void onClick(DialogInterface dialog, int which) { 261 switch (which) { 262 case DialogInterface.BUTTON_POSITIVE: 263 mResultMap.put("which", "positive"); 264 break; 265 case DialogInterface.BUTTON_NEGATIVE: 266 mResultMap.put("which", "negative"); 267 break; 268 case DialogInterface.BUTTON_NEUTRAL: 269 mResultMap.put("which", "neutral"); 270 271 break; 272 } 273 setResult(); 274 } 275 }; 276 if (mNegativeButtonText != null) { 277 builder.setNegativeButton(mNegativeButtonText, buttonListener); 278 } 279 if (mPositiveButtonText != null) { 280 builder.setPositiveButton(mPositiveButtonText, buttonListener); 281 } 282 if (mNeutralButtonText != null) { 283 builder.setNeutralButton(mNeutralButtonText, buttonListener); 284 } 285 } 286 287 private void setResult() { 288 dismissDialog(); 289 if (mInputType == InputType.PLAIN_TEXT || mInputType == InputType.PASSWORD) { 290 mResultMap.put("value", mEditText.getText().toString()); 291 } 292 setResult(mResultMap); 293 } 294 295 } 296