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