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