Home | History | Annotate | Download | only in ui
      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