Home | History | Annotate | Download | only in ui
      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 
     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 
     71   public void setPositiveButtonText(String text) {
     72     mPositiveButtonText = text;
     73   }
     74 
     75   public void setNegativeButtonText(String text) {
     76     mNegativeButtonText = text;
     77   }
     78 
     79   public void setNeutralButtonText(String text) {
     80     mNeutralButtonText = text;
     81   }
     82 
     83   /**
     84    * Set list items.
     85    *
     86    * @param items
     87    */
     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    */
    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    */
    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    */
    138   public Set<Integer> getSelectedItems() {
    139     return mSelectedItems;
    140   }
    141 
    142   public void setTextInput(String defaultText) {
    143     mDefaultText = defaultText;
    144     mInputType = InputType.PLAIN_TEXT;
    145     setEditInputType("text");
    146   }
    147 
    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 
    163   public void setPasswordInput() {
    164     mInputType = InputType.PASSWORD;
    165   }
    166 
    167   @Override
    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 
    242   private CharSequence[] getItemsAsCharSequenceArray() {
    243     return mItems.toArray(new CharSequence[mItems.size()]);
    244   }
    245 
    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