Home | History | Annotate | Download | only in webkit
      1 /*
      2  * Copyright (C) 2013 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 android.webkit;
     18 
     19 import android.app.Activity;
     20 import android.app.AlertDialog;
     21 import android.content.Context;
     22 import android.content.DialogInterface;
     23 import android.os.Message;
     24 import android.util.Log;
     25 import android.view.LayoutInflater;
     26 import android.view.View;
     27 import android.widget.EditText;
     28 import android.widget.TextView;
     29 
     30 import java.net.MalformedURLException;
     31 import java.net.URL;
     32 
     33 /**
     34  * Helper class to create JavaScript dialogs. It is used by
     35  * different WebView implementations.
     36  *
     37  * @hide Helper class for internal use
     38  */
     39 public class JsDialogHelper {
     40 
     41     private static final String TAG = "JsDialogHelper";
     42 
     43     // Dialog types
     44     public static final int ALERT   = 1;
     45     public static final int CONFIRM = 2;
     46     public static final int PROMPT  = 3;
     47     public static final int UNLOAD  = 4;
     48 
     49     private final String mDefaultValue;
     50     private final JsPromptResult mResult;
     51     private final String mMessage;
     52     private final int mType;
     53     private final String mUrl;
     54 
     55     public JsDialogHelper(JsPromptResult result, int type, String defaultValue, String message,
     56             String url) {
     57         mResult = result;
     58         mDefaultValue = defaultValue;
     59         mMessage = message;
     60         mType = type;
     61         mUrl = url;
     62     }
     63 
     64     public JsDialogHelper(JsPromptResult result, Message msg) {
     65         mResult = result;
     66         mDefaultValue = msg.getData().getString("default");
     67         mMessage = msg.getData().getString("message");
     68         mType = msg.getData().getInt("type");
     69         mUrl = msg.getData().getString("url");
     70     }
     71 
     72     public boolean invokeCallback(WebChromeClient client, WebView webView) {
     73         switch (mType) {
     74             case ALERT:
     75                 return client.onJsAlert(webView, mUrl, mMessage, mResult);
     76             case CONFIRM:
     77                 return client.onJsConfirm(webView, mUrl, mMessage, mResult);
     78             case UNLOAD:
     79                 return client.onJsBeforeUnload(webView, mUrl, mMessage, mResult);
     80             case PROMPT:
     81                 return client.onJsPrompt(webView, mUrl, mMessage, mDefaultValue, mResult);
     82             default:
     83                 throw new IllegalArgumentException("Unexpected type: " + mType);
     84         }
     85     }
     86 
     87     public void showDialog(Context context) {
     88         if (!canShowAlertDialog(context)) {
     89             Log.w(TAG, "Cannot create a dialog, the WebView context is not an Activity");
     90             mResult.cancel();
     91             return;
     92         }
     93 
     94         String title, displayMessage;
     95         int positiveTextId, negativeTextId;
     96         if (mType == UNLOAD) {
     97             title = context.getString(com.android.internal.R.string.js_dialog_before_unload_title);
     98             displayMessage = context.getString(
     99                     com.android.internal.R.string.js_dialog_before_unload, mMessage);
    100             positiveTextId = com.android.internal.R.string.js_dialog_before_unload_positive_button;
    101             negativeTextId = com.android.internal.R.string.js_dialog_before_unload_negative_button;
    102         } else {
    103             title = getJsDialogTitle(context);
    104             displayMessage = mMessage;
    105             positiveTextId = com.android.internal.R.string.ok;
    106             negativeTextId = com.android.internal.R.string.cancel;
    107         }
    108         AlertDialog.Builder builder = new AlertDialog.Builder(context);
    109         builder.setTitle(title);
    110         builder.setOnCancelListener(new CancelListener());
    111         if (mType != PROMPT) {
    112             builder.setMessage(displayMessage);
    113             builder.setPositiveButton(positiveTextId, new PositiveListener(null));
    114         } else {
    115             final View view = LayoutInflater.from(context).inflate(
    116                     com.android.internal.R.layout.js_prompt, null);
    117             EditText edit = ((EditText) view.findViewById(com.android.internal.R.id.value));
    118             edit.setText(mDefaultValue);
    119             builder.setPositiveButton(positiveTextId, new PositiveListener(edit));
    120             ((TextView) view.findViewById(com.android.internal.R.id.message)).setText(mMessage);
    121             builder.setView(view);
    122         }
    123         if (mType != ALERT) {
    124             builder.setNegativeButton(negativeTextId, new CancelListener());
    125         }
    126         builder.show();
    127     }
    128 
    129     private class CancelListener implements DialogInterface.OnCancelListener,
    130             DialogInterface.OnClickListener {
    131         @Override
    132         public void onCancel(DialogInterface dialog) {
    133             mResult.cancel();
    134         }
    135         @Override
    136         public void onClick(DialogInterface dialog, int which) {
    137             mResult.cancel();
    138         }
    139     }
    140 
    141     private class PositiveListener implements DialogInterface.OnClickListener {
    142         private final EditText mEdit;
    143 
    144         public PositiveListener(EditText edit) {
    145             mEdit = edit;
    146         }
    147 
    148         @Override
    149         public void onClick(DialogInterface dialog, int which) {
    150             if (mEdit == null) {
    151                 mResult.confirm();
    152             } else {
    153                 mResult.confirm(mEdit.getText().toString());
    154             }
    155         }
    156     }
    157 
    158     private String getJsDialogTitle(Context context) {
    159         String title = mUrl;
    160         if (URLUtil.isDataUrl(mUrl)) {
    161             // For data: urls, we just display 'JavaScript' similar to Chrome.
    162             title = context.getString(com.android.internal.R.string.js_dialog_title_default);
    163         } else {
    164             try {
    165                 URL alertUrl = new URL(mUrl);
    166                 // For example: "The page at 'http://www.mit.edu' says:"
    167                 title = context.getString(com.android.internal.R.string.js_dialog_title,
    168                         alertUrl.getProtocol() + "://" + alertUrl.getHost());
    169             } catch (MalformedURLException ex) {
    170                 // do nothing. just use the url as the title
    171             }
    172         }
    173         return title;
    174     }
    175 
    176     private static boolean canShowAlertDialog(Context context) {
    177         // We can only display the alert dialog if mContext is
    178         // an Activity context.
    179         // FIXME: Should we display dialogs if mContext does
    180         // not have the window focus (e.g. if the user is viewing
    181         // another Activity when the alert should be displayed) ?
    182         // See bug 3166409
    183         return context instanceof Activity;
    184     }
    185 }
    186