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