summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/java/android/app/Notification.java127
-rw-r--r--core/java/android/hardware/Sensor.java4
-rw-r--r--core/java/android/view/SurfaceView.java1
-rw-r--r--core/java/android/view/ViewGroupOverlay.java3
-rw-r--r--core/java/android/view/ViewOverlay.java3
-rw-r--r--core/java/android/view/WindowManager.java6
-rw-r--r--core/java/android/webkit/CallbackProxy.java243
-rw-r--r--core/java/android/webkit/JsDialogHelper.java185
-rw-r--r--core/res/res/values/strings.xml11
-rw-r--r--core/res/res/values/symbols.xml3
10 files changed, 331 insertions, 255 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a7543a8..8d994c4 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -427,22 +427,48 @@ public class Notification implements Parcelable
public String[] kind;
/**
- * Extra key for people values (type TBD).
- *
+ * Additional semantic data to be carried around with this Notification.
* @hide
*/
- public static final String EXTRA_PEOPLE = "android.people";
+ public Bundle extras = new Bundle();
+
+ // extras keys for Builder inputs
/** @hide */
public static final String EXTRA_TITLE = "android.title";
/** @hide */
+ public static final String EXTRA_TITLE_BIG = EXTRA_TITLE + ".big";
+ /** @hide */
public static final String EXTRA_TEXT = "android.text";
/** @hide */
- public static final String EXTRA_SUBTEXT = "android.subtext";
+ public static final String EXTRA_SUB_TEXT = "android.subText";
+ /** @hide */
+ public static final String EXTRA_INFO_TEXT = "android.infoText";
+ /** @hide */
+ public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
/** @hide */
public static final String EXTRA_SMALL_ICON = "android.icon";
+ /** @hide */
+ public static final String EXTRA_LARGE_ICON = "android.largeIcon";
+ /** @hide */
+ public static final String EXTRA_LARGE_ICON_BIG = EXTRA_LARGE_ICON + ".big";
+ /** @hide */
+ public static final String EXTRA_PROGRESS = "android.progress";
+ /** @hide */
+ public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
+ /** @hide */
+ public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+ /** @hide */
+ public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+ /** @hide */
+ public static final String EXTRA_SHOW_WHEN = "android.showWhen";
+ /** @hide from BigPictureStyle */
+ public static final String EXTRA_PICTURE = "android.picture";
+ /** @hide from InboxStyle */
+ public static final String EXTRA_TEXT_LINES = "android.textLines";
+ // extras keys for other interesting pieces of information
/** @hide */
- public Bundle extras = new Bundle();
+ public static final String EXTRA_PEOPLE = "android.people";
/**
* Structure to encapsulate an "action", including title and icon, that can be attached to a Notification.
@@ -1621,16 +1647,26 @@ public class Notification implements Parcelable
mActions.toArray(n.actions);
}
- n.extras = mExtras != null ? new Bundle(mExtras) : new Bundle();
+ return n;
+ }
+ /**
+ * Capture, in the provided bundle, semantic information used in the construction of
+ * this Notification object.
+ * @hide
+ */
+ public void addExtras(Bundle extras) {
// Store original information used in the construction of this object
- n.extras.putCharSequence(EXTRA_TITLE, mContentTitle);
- n.extras.putCharSequence(EXTRA_TEXT, mContentText);
- n.extras.putCharSequence(EXTRA_SUBTEXT, mSubText);
- n.extras.putInt(EXTRA_SMALL_ICON, mSmallIcon);
- //n.extras.putByteArray(EXTRA_LARGE_ICON, ...
-
- return n;
+ extras.putCharSequence(EXTRA_TITLE, mContentTitle);
+ extras.putCharSequence(EXTRA_TEXT, mContentText);
+ extras.putCharSequence(EXTRA_SUB_TEXT, mSubText);
+ extras.putCharSequence(EXTRA_INFO_TEXT, mContentInfo);
+ extras.putInt(EXTRA_SMALL_ICON, mSmallIcon);
+ extras.putInt(EXTRA_PROGRESS, mProgress);
+ extras.putInt(EXTRA_PROGRESS_MAX, mProgressMax);
+ extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, mProgressIndeterminate);
+ extras.putBoolean(EXTRA_SHOW_CHRONOMETER, mUseChronometer);
+ extras.putBoolean(EXTRA_SHOW_WHEN, mShowWhen);
}
/**
@@ -1646,11 +1682,22 @@ public class Notification implements Parcelable
* object.
*/
public Notification build() {
+ final Notification n;
+
if (mStyle != null) {
- return mStyle.build();
+ n = mStyle.build();
} else {
- return buildUnstyled();
+ n = buildUnstyled();
}
+
+ n.extras = mExtras != null ? new Bundle(mExtras) : new Bundle();
+
+ addExtras(n.extras);
+ if (mStyle != null) {
+ mStyle.addExtras(n.extras);
+ }
+
+ return n;
}
/**
@@ -1664,7 +1711,6 @@ public class Notification implements Parcelable
}
}
-
/**
* An object that can apply a rich notification style to a {@link Notification.Builder}
* object.
@@ -1739,6 +1785,18 @@ public class Notification implements Parcelable
return contentView;
}
+ /**
+ * @hide
+ */
+ public void addExtras(Bundle extras) {
+ if (mSummaryTextSet) {
+ extras.putCharSequence(EXTRA_SUMMARY_TEXT, mSummaryText);
+ }
+ if (mBigContentTitle != null) {
+ extras.putCharSequence(EXTRA_TITLE_BIG, mBigContentTitle);
+ }
+ }
+
public abstract Notification build();
}
@@ -1813,6 +1871,18 @@ public class Notification implements Parcelable
return contentView;
}
+ /**
+ * @hide
+ */
+ public void addExtras(Bundle extras) {
+ super.addExtras(extras);
+
+ if (mBigLargeIconSet) {
+ extras.putParcelable(EXTRA_LARGE_ICON_BIG, mBigLargeIcon);
+ }
+ extras.putParcelable(EXTRA_PICTURE, mPicture);
+ }
+
@Override
public Notification build() {
checkBuilder();
@@ -1878,6 +1948,15 @@ public class Notification implements Parcelable
return this;
}
+ /**
+ * @hide
+ */
+ public void addExtras(Bundle extras) {
+ super.addExtras(extras);
+
+ extras.putCharSequence(EXTRA_TEXT, mBigText);
+ }
+
private RemoteViews makeBigContentView() {
// Remove the content text so line3 only shows if you have a summary
final boolean hadThreeLines = (mBuilder.mContentText != null && mBuilder.mSubText != null);
@@ -1964,6 +2043,15 @@ public class Notification implements Parcelable
return this;
}
+ /**
+ * @hide
+ */
+ public void addExtras(Bundle extras) {
+ super.addExtras(extras);
+ CharSequence[] a = new CharSequence[mTexts.size()];
+ extras.putCharSequenceArray(EXTRA_TEXT_LINES, mTexts.toArray(a));
+ }
+
private RemoteViews makeBigContentView() {
// Remove the content text so line3 disappears unless you have a summary
mBuilder.mContentText = null;
@@ -2005,13 +2093,6 @@ public class Notification implements Parcelable
Notification wip = mBuilder.buildUnstyled();
wip.bigContentView = makeBigContentView();
- StringBuilder builder = new StringBuilder();
- for (CharSequence str : mTexts) {
- builder.append(str);
- builder.append("\n");
- }
- wip.extras.putCharSequence(EXTRA_TEXT, builder);
-
return wip;
}
}
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 074f8fe..71a5382 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -188,6 +188,8 @@ public final class Sensor {
// Upon detection of an event, the sensor deactivates itself and then sends a single event.
static int REPORTING_MODE_ONE_SHOT = 3;
+ // TODO(): The following arrays are fragile and error-prone. This needs to be refactored.
+
// Note: This needs to be updated, whenever a new sensor is added.
private static int[] sSensorReportingModes = {
REPORTING_MODE_CONTINUOUS, REPORTING_MODE_CONTINUOUS, REPORTING_MODE_CONTINUOUS,
@@ -201,7 +203,7 @@ public final class Sensor {
// Holds the maximum length of the values array associated with {@link SensorEvent} or
// {@link TriggerEvent} for the Sensor
private static int[] sMaxLengthValuesArray = {
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3,
6, 4, 6, 1 };
static int getReportingMode(Sensor sensor) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 5d0f523..14fa9cb 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -480,6 +480,7 @@ public class SurfaceView extends View {
if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
}
+ mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
if (mWindow == null) {
Display display = getDisplay();
diff --git a/core/java/android/view/ViewGroupOverlay.java b/core/java/android/view/ViewGroupOverlay.java
index c1b24f2..16afc5d 100644
--- a/core/java/android/view/ViewGroupOverlay.java
+++ b/core/java/android/view/ViewGroupOverlay.java
@@ -47,7 +47,8 @@ public class ViewGroupOverlay extends ViewOverlay {
* animation effect.</p>
*
* <p>If the view has a parent, the view will be removed from that parent
- * before being added to the overlay. Also, the view will be repositioned
+ * before being added to the overlay. Also, if that parent is attached
+ * in the current view hierarchy, the view will be repositioned
* such that it is in the same relative location inside the activity. For
* example, if the view's current parent lies 100 pixels to the right
* and 200 pixels down from the origin of the overlay's
diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java
index 78e2597..fe5b990 100644
--- a/core/java/android/view/ViewOverlay.java
+++ b/core/java/android/view/ViewOverlay.java
@@ -157,7 +157,8 @@ public class ViewOverlay {
public void add(View child) {
if (child.getParent() instanceof ViewGroup) {
ViewGroup parent = (ViewGroup) child.getParent();
- if (parent != mHostView) {
+ if (parent != mHostView && parent.getParent() != null &&
+ parent.mAttachInfo != null) {
// Moving to different container; figure out how to position child such that
// it is in the same location on the screen
int[] parentLocation = new int[2];
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 96ef0b4..48630a4 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1012,6 +1012,12 @@ public interface WindowManager extends ViewManager {
public static final int PRIVATE_FLAG_FORCE_SHOW_NAV_BAR = 0x00000020;
/**
+ * Never animate position changes of the window.
+ *
+ * {@hide} */
+ public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 0x00000040;
+
+ /**
* Control flags that are private to the platform.
* @hide
*/
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index a326da2..312af71 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -17,10 +17,8 @@
package android.webkit;
import android.app.Activity;
-import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
@@ -33,10 +31,6 @@ import android.os.SystemClock;
import android.provider.Browser;
import android.util.Log;
import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.EditText;
-import android.widget.TextView;
import com.android.internal.R;
import java.net.MalformedURLException;
@@ -92,10 +86,7 @@ class CallbackProxy extends Handler {
private static final int CREATE_WINDOW = 109;
private static final int CLOSE_WINDOW = 110;
private static final int SAVE_PASSWORD = 111;
- private static final int JS_ALERT = 112;
- private static final int JS_CONFIRM = 113;
- private static final int JS_PROMPT = 114;
- private static final int JS_UNLOAD = 115;
+ private static final int JS_DIALOG = 112;
private static final int ASYNC_KEYEVENTS = 116;
private static final int DOWNLOAD_FILE = 118;
private static final int REPORT_ERROR = 119;
@@ -566,188 +557,12 @@ class CallbackProxy extends Handler {
}
break;
- case JS_ALERT:
+ case JS_DIALOG:
if (mWebChromeClient != null) {
final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
- final JsResult res = receiver.mJsResult;
- String message = msg.getData().getString("message");
- String url = msg.getData().getString("url");
- if (!mWebChromeClient.onJsAlert(mWebView.getWebView(), url, message,
- res)) {
- if (!canShowAlertDialog()) {
- res.cancel();
- receiver.setReady();
- break;
- }
- new AlertDialog.Builder(mContext)
- .setTitle(getJsDialogTitle(url))
- .setMessage(message)
- .setPositiveButton(R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(
- DialogInterface dialog,
- int which) {
- res.confirm();
- }
- })
- .setOnCancelListener(
- new DialogInterface.OnCancelListener() {
- public void onCancel(
- DialogInterface dialog) {
- res.cancel();
- }
- })
- .show();
- }
- receiver.setReady();
- }
- break;
-
- case JS_CONFIRM:
- if (mWebChromeClient != null) {
- final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
- final JsResult res = receiver.mJsResult;
- String message = msg.getData().getString("message");
- String url = msg.getData().getString("url");
- if (!mWebChromeClient.onJsConfirm(mWebView.getWebView(), url, message,
- res)) {
- if (!canShowAlertDialog()) {
- res.cancel();
- receiver.setReady();
- break;
- }
- new AlertDialog.Builder(mContext)
- .setTitle(getJsDialogTitle(url))
- .setMessage(message)
- .setPositiveButton(R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(
- DialogInterface dialog,
- int which) {
- res.confirm();
- }})
- .setNegativeButton(R.string.cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(
- DialogInterface dialog,
- int which) {
- res.cancel();
- }})
- .setOnCancelListener(
- new DialogInterface.OnCancelListener() {
- public void onCancel(
- DialogInterface dialog) {
- res.cancel();
- }
- })
- .show();
- }
- // Tell the JsResult that it is ready for client
- // interaction.
- receiver.setReady();
- }
- break;
-
- case JS_PROMPT:
- if (mWebChromeClient != null) {
- final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
- final JsPromptResult res = receiver.mJsResult;
- String message = msg.getData().getString("message");
- String defaultVal = msg.getData().getString("default");
- String url = msg.getData().getString("url");
- if (!mWebChromeClient.onJsPrompt(mWebView.getWebView(), url, message,
- defaultVal, res)) {
- if (!canShowAlertDialog()) {
- res.cancel();
- receiver.setReady();
- break;
- }
- final LayoutInflater factory = LayoutInflater
- .from(mContext);
- final View view = factory.inflate(R.layout.js_prompt,
- null);
- final EditText v = (EditText) view
- .findViewById(R.id.value);
- v.setText(defaultVal);
- ((TextView) view.findViewById(R.id.message))
- .setText(message);
- new AlertDialog.Builder(mContext)
- .setTitle(getJsDialogTitle(url))
- .setView(view)
- .setPositiveButton(R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(
- DialogInterface dialog,
- int whichButton) {
- res.confirm(v.getText()
- .toString());
- }
- })
- .setNegativeButton(R.string.cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(
- DialogInterface dialog,
- int whichButton) {
- res.cancel();
- }
- })
- .setOnCancelListener(
- new DialogInterface.OnCancelListener() {
- public void onCancel(
- DialogInterface dialog) {
- res.cancel();
- }
- })
- .show();
- }
- // Tell the JsResult that it is ready for client
- // interaction.
- receiver.setReady();
- }
- break;
-
- case JS_UNLOAD:
- if (mWebChromeClient != null) {
- final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
- final JsResult res = receiver.mJsResult;
- String message = msg.getData().getString("message");
- String url = msg.getData().getString("url");
- if (!mWebChromeClient.onJsBeforeUnload(mWebView.getWebView(), url,
- message, res)) {
- if (!canShowAlertDialog()) {
- res.cancel();
- receiver.setReady();
- break;
- }
- final String m = mContext.getString(
- R.string.js_dialog_before_unload, message);
- new AlertDialog.Builder(mContext)
- .setMessage(m)
- .setPositiveButton(R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(
- DialogInterface dialog,
- int which) {
- res.confirm();
- }
- })
- .setNegativeButton(R.string.cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(
- DialogInterface dialog,
- int which) {
- res.cancel();
- }
- })
- .setOnCancelListener(
- new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(
- DialogInterface dialog) {
- res.cancel();
- }
- })
- .show();
+ JsDialogHelper helper = new JsDialogHelper(receiver.mJsResult, msg);
+ if (!helper.invokeCallback(mWebChromeClient, mWebView.getWebView())) {
+ helper.showDialog(mContext);
}
receiver.setReady();
}
@@ -757,7 +572,7 @@ class CallbackProxy extends Handler {
if(mWebChromeClient != null) {
final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
final JsResult res = receiver.mJsResult;
- if(mWebChromeClient.onJsTimeout()) {
+ if (mWebChromeClient.onJsTimeout()) {
res.confirm();
} else {
res.cancel();
@@ -895,24 +710,6 @@ class CallbackProxy extends Handler {
sendMessage(obtainMessage(SWITCH_OUT_HISTORY));
}
- private String getJsDialogTitle(String url) {
- String title = url;
- if (URLUtil.isDataUrl(url)) {
- // For data: urls, we just display 'JavaScript' similar to Safari.
- title = mContext.getString(R.string.js_dialog_title_default);
- } else {
- try {
- URL aUrl = new URL(url);
- // For example: "The page at 'http://www.mit.edu' says:"
- title = mContext.getString(R.string.js_dialog_title,
- aUrl.getProtocol() + "://" + aUrl.getHost());
- } catch (MalformedURLException ex) {
- // do nothing. just use the url as the title
- }
- }
- return title;
- }
-
//--------------------------------------------------------------------------
// WebViewClient functions.
// NOTE: shouldOverrideKeyEvent is never called from the WebCore thread so
@@ -1332,9 +1129,10 @@ class CallbackProxy extends Handler {
return;
}
JsResultReceiver result = new JsResultReceiver();
- Message alert = obtainMessage(JS_ALERT, result);
+ Message alert = obtainMessage(JS_DIALOG, result);
alert.getData().putString("message", message);
alert.getData().putString("url", url);
+ alert.getData().putInt("type", JsDialogHelper.ALERT);
sendMessageToUiThreadSync(alert);
}
@@ -1345,9 +1143,10 @@ class CallbackProxy extends Handler {
return false;
}
JsResultReceiver result = new JsResultReceiver();
- Message confirm = obtainMessage(JS_CONFIRM, result);
+ Message confirm = obtainMessage(JS_DIALOG, result);
confirm.getData().putString("message", message);
confirm.getData().putString("url", url);
+ confirm.getData().putInt("type", JsDialogHelper.CONFIRM);
sendMessageToUiThreadSync(confirm);
return result.mJsResult.getResult();
}
@@ -1359,10 +1158,11 @@ class CallbackProxy extends Handler {
return null;
}
JsResultReceiver result = new JsResultReceiver();
- Message prompt = obtainMessage(JS_PROMPT, result);
+ Message prompt = obtainMessage(JS_DIALOG, result);
prompt.getData().putString("message", message);
prompt.getData().putString("default", defaultValue);
prompt.getData().putString("url", url);
+ prompt.getData().putInt("type", JsDialogHelper.PROMPT);
sendMessageToUiThreadSync(prompt);
return result.mJsResult.getStringResult();
}
@@ -1374,10 +1174,11 @@ class CallbackProxy extends Handler {
return true;
}
JsResultReceiver result = new JsResultReceiver();
- Message confirm = obtainMessage(JS_UNLOAD, result);
- confirm.getData().putString("message", message);
- confirm.getData().putString("url", url);
- sendMessageToUiThreadSync(confirm);
+ Message unload = obtainMessage(JS_DIALOG, result);
+ unload.getData().putString("message", message);
+ unload.getData().putString("url", url);
+ unload.getData().putInt("type", JsDialogHelper.UNLOAD);
+ sendMessageToUiThreadSync(unload);
return result.mJsResult.getResult();
}
@@ -1595,16 +1396,6 @@ class CallbackProxy extends Handler {
sendMessage(msg);
}
- boolean canShowAlertDialog() {
- // We can only display the alert dialog if mContext is
- // an Activity context.
- // FIXME: Should we display dialogs if mContext does
- // not have the window focus (e.g. if the user is viewing
- // another Activity when the alert should be displayed?
- // See bug 3166409
- return mContext instanceof Activity;
- }
-
private synchronized void sendMessageToUiThreadSync(Message msg) {
sendMessage(msg);
WebCoreThreadWatchdog.pause();
diff --git a/core/java/android/webkit/JsDialogHelper.java b/core/java/android/webkit/JsDialogHelper.java
new file mode 100644
index 0000000..bb0339e
--- /dev/null
+++ b/core/java/android/webkit/JsDialogHelper.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Message;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * Helper class to create JavaScript dialogs. It is used by
+ * different WebView implementations.
+ *
+ * @hide Helper class for internal use
+ */
+public class JsDialogHelper {
+
+ private static final String TAG = "JsDialogHelper";
+
+ // Dialog types
+ public static final int ALERT = 1;
+ public static final int CONFIRM = 2;
+ public static final int PROMPT = 3;
+ public static final int UNLOAD = 4;
+
+ private final String mDefaultValue;
+ private final JsPromptResult mResult;
+ private final String mMessage;
+ private final int mType;
+ private final String mUrl;
+
+ public JsDialogHelper(JsPromptResult result, int type, String defaultValue, String message,
+ String url) {
+ mResult = result;
+ mDefaultValue = defaultValue;
+ mMessage = message;
+ mType = type;
+ mUrl = url;
+ }
+
+ public JsDialogHelper(JsPromptResult result, Message msg) {
+ mResult = result;
+ mDefaultValue = msg.getData().getString("default");
+ mMessage = msg.getData().getString("message");
+ mType = msg.getData().getInt("type");
+ mUrl = msg.getData().getString("url");
+ }
+
+ public boolean invokeCallback(WebChromeClient client, WebView webView) {
+ switch (mType) {
+ case ALERT:
+ return client.onJsAlert(webView, mUrl, mMessage, mResult);
+ case CONFIRM:
+ return client.onJsConfirm(webView, mUrl, mMessage, mResult);
+ case UNLOAD:
+ return client.onJsBeforeUnload(webView, mUrl, mMessage, mResult);
+ case PROMPT:
+ return client.onJsPrompt(webView, mUrl, mMessage, mDefaultValue, mResult);
+ default:
+ throw new IllegalArgumentException("Unexpected type: " + mType);
+ }
+ }
+
+ public void showDialog(Context context) {
+ if (!canShowAlertDialog(context)) {
+ Log.w(TAG, "Cannot create a dialog, the WebView context is not an Activity");
+ mResult.cancel();
+ return;
+ }
+
+ String title, displayMessage;
+ int positiveTextId, negativeTextId;
+ if (mType == UNLOAD) {
+ title = context.getString(com.android.internal.R.string.js_dialog_before_unload_title);
+ displayMessage = context.getString(
+ com.android.internal.R.string.js_dialog_before_unload, mMessage);
+ positiveTextId = com.android.internal.R.string.js_dialog_before_unload_positive_button;
+ negativeTextId = com.android.internal.R.string.js_dialog_before_unload_negative_button;
+ } else {
+ title = getJsDialogTitle(context);
+ displayMessage = mMessage;
+ positiveTextId = com.android.internal.R.string.ok;
+ negativeTextId = com.android.internal.R.string.cancel;
+ }
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(title);
+ builder.setOnCancelListener(new CancelListener());
+ if (mType != PROMPT) {
+ builder.setMessage(displayMessage);
+ builder.setPositiveButton(positiveTextId, new PositiveListener(null));
+ } else {
+ final View view = LayoutInflater.from(context).inflate(
+ com.android.internal.R.layout.js_prompt, null);
+ EditText edit = ((EditText) view.findViewById(com.android.internal.R.id.value));
+ edit.setText(mDefaultValue);
+ builder.setPositiveButton(positiveTextId, new PositiveListener(edit));
+ ((TextView) view.findViewById(com.android.internal.R.id.message)).setText(mMessage);
+ builder.setView(view);
+ }
+ if (mType != ALERT) {
+ builder.setNegativeButton(negativeTextId, new CancelListener());
+ }
+ builder.show();
+ }
+
+ private class CancelListener implements DialogInterface.OnCancelListener,
+ DialogInterface.OnClickListener {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ mResult.cancel();
+ }
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mResult.cancel();
+ }
+ }
+
+ private class PositiveListener implements DialogInterface.OnClickListener {
+ private final EditText mEdit;
+
+ public PositiveListener(EditText edit) {
+ mEdit = edit;
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (mEdit == null) {
+ mResult.confirm();
+ } else {
+ mResult.confirm(mEdit.getText().toString());
+ }
+ }
+ }
+
+ private String getJsDialogTitle(Context context) {
+ String title = mUrl;
+ if (URLUtil.isDataUrl(mUrl)) {
+ // For data: urls, we just display 'JavaScript' similar to Chrome.
+ title = context.getString(com.android.internal.R.string.js_dialog_title_default);
+ } else {
+ try {
+ URL alertUrl = new URL(mUrl);
+ // For example: "The page at 'http://www.mit.edu' says:"
+ title = context.getString(com.android.internal.R.string.js_dialog_title,
+ alertUrl.getProtocol() + "://" + alertUrl.getHost());
+ } catch (MalformedURLException ex) {
+ // do nothing. just use the url as the title
+ }
+ }
+ return title;
+ }
+
+ private static boolean canShowAlertDialog(Context context) {
+ // We can only display the alert dialog if mContext is
+ // an Activity context.
+ // FIXME: Should we display dialogs if mContext does
+ // not have the window focus (e.g. if the user is viewing
+ // another Activity when the alert should be displayed) ?
+ // See bug 3166409
+ return context instanceof Activity;
+ }
+}
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a0e1603..3361ab7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2411,9 +2411,14 @@
<string name="js_dialog_title">The page at \"<xliff:g id="title">%s</xliff:g>\" says:</string>
<!-- Default title for a javascript dialog -->
<string name="js_dialog_title_default">JavaScript</string>
- <!-- Message in a javascript dialog asking if the user wishes to leave the
- current page -->
- <string name="js_dialog_before_unload">Navigate away from this page?\n\n<xliff:g id="message">%s</xliff:g>\n\nTouch OK to continue, or Cancel to stay on the current page.</string>
+ <!-- Title for the unload javascript dialog -->
+ <string name="js_dialog_before_unload_title">Confirm Navigation</string>
+ <!-- Text for the positive button on the unload javascript dialog -->
+ <string name="js_dialog_before_unload_positive_button">Leave this Page</string>
+ <!-- Text for the negative button on the unload javascript dialog -->
+ <string name="js_dialog_before_unload_negative_button">Stay on this Page</string>
+ <!-- Message in a javascript dialog asking if the user wishes to leave the current page -->
+ <string name="js_dialog_before_unload"><xliff:g id="message">%s</xliff:g>\n\nAre you sure you want to navigate away from this page?</string>
<!-- Title of the WebView save password dialog. If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. -->
<string name="save_password_label">Confirm</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e06bcd1..45ea182 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -549,6 +549,9 @@
<java-symbol type="string" name="ime_action_search" />
<java-symbol type="string" name="ime_action_send" />
<java-symbol type="string" name="invalidPin" />
+ <java-symbol type="string" name="js_dialog_before_unload_positive_button" />
+ <java-symbol type="string" name="js_dialog_before_unload_negative_button" />
+ <java-symbol type="string" name="js_dialog_before_unload_title" />
<java-symbol type="string" name="js_dialog_before_unload" />
<java-symbol type="string" name="js_dialog_title" />
<java-symbol type="string" name="js_dialog_title_default" />