Merge change 7402 into donut
* changes:
Added fade-in out animation for compatible apps (This CL only add this when the app on the top is in compatibility mode for now. I need some help to do the same when the closing app is in compatibility mode) Refactored DimAnimator
diff --git a/api/current.xml b/api/current.xml
index a10109c..6a5680d 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -111383,6 +111383,144 @@
>
</field>
</class>
+<class name="TextToSpeech.Engine"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="TextToSpeech.Engine"
+ type="android.speech.tts.TextToSpeech.Engine"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="CHECK_VOICE_DATA_BAD_DATA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHECK_VOICE_DATA_FAIL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHECK_VOICE_DATA_MISSING_DATA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHECK_VOICE_DATA_MISSING_VOLUME"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHECK_VOICE_DATA_PASS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TTS_DEFAULT_STREAM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TTS_KEY_PARAM_STREAM"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""streamType""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TTS_KEY_PARAM_UTTERANCE_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""utteranceId""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="VOICE_DATA_FILES"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""dataFiles""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="VOICE_DATA_FILES_INFO"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""dataFilesInfo""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="VOICE_DATA_ROOT_DIRECTORY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""dataRoot""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<interface name="TextToSpeech.OnInitListener"
abstract="true"
static="true"
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 1330912..444f222 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.DialogInterface;
+import android.content.ComponentName;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
@@ -784,8 +785,17 @@
* This hook is called when the user signals the desire to start a search.
*/
public boolean onSearchRequested() {
- // not during dialogs, no.
- return false;
+ final SearchManager searchManager = (SearchManager) mContext
+ .getSystemService(Context.SEARCH_SERVICE);
+
+ // associate search with owner activity if possible (otherwise it will default to
+ // global search).
+ final ComponentName appName = mOwnerActivity == null ? null
+ : mOwnerActivity.getComponentName();
+ final boolean globalSearch = (appName == null);
+ searchManager.startSearch(null, false, appName, null, globalSearch);
+ dismiss();
+ return true;
}
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 13eb034..1283b8f 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -337,16 +337,7 @@
mActivityContext = mSearchable.getActivityContext(getContext());
// show the dialog. this will call onStart().
- if (!isShowing()) {
- // First make sure the keyboard is showing (if needed), so that we get the right height
- // for the dropdown to respect the IME.
- if (getContext().getResources().getConfiguration().hardKeyboardHidden ==
- Configuration.HARDKEYBOARDHIDDEN_YES) {
- InputMethodManager inputManager = (InputMethodManager)
- getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- inputManager.showSoftInputUnchecked(0, null);
- }
-
+ if (!isShowing()) {
// The Dialog uses a ContextThemeWrapper for the context; use this to change the
// theme out from underneath us, between the global search theme and the in-app
// search theme. They are identical except that the global search theme does not
@@ -1535,7 +1526,22 @@
@Override
public void performCompletion() {
}
-
+
+ /**
+ * We override this method to be sure and show the soft keyboard if appropriate when
+ * the TextView has focus.
+ */
+ @Override
+ public void onWindowFocusChanged(boolean hasWindowFocus) {
+ super.onWindowFocusChanged(hasWindowFocus);
+
+ if (hasWindowFocus) {
+ InputMethodManager inputManager = (InputMethodManager)
+ getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputManager.showSoftInput(this, 0);
+ }
+ }
+
/**
* We override this method so that we can allow a threshold of zero, which ACTV does not.
*/
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 8530c35..a2e0ba0a 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -57,6 +57,9 @@
*
* <p>This field corresponds to the <code>android:updatePeriodMillis</code> attribute in
* the AppWidget meta-data file.
+ *
+ * <p class="note"><b>Note:</b> Updates requested with <code>updatePeriodMillis</code>
+ * will not be delivered more than once every 30 minutes.</p>
*/
public int updatePeriodMillis;
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 8de938d..a9aa1ee 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -34,6 +34,7 @@
import android.util.SparseArray;
import android.util.TypedValue;
import android.util.LongSparseArray;
+import android.view.Display;
import java.io.IOException;
import java.io.InputStream;
@@ -87,6 +88,7 @@
PluralRules mPluralRule;
private final CompatibilityInfo mCompatibilityInfo;
+ private Display mDefaultDisplay;
private static final LongSparseArray<Object> EMPTY_ARRAY = new LongSparseArray<Object>() {
@Override
@@ -1915,6 +1917,24 @@
+ Integer.toHexString(id));
}
+ /**
+ * Returns the display adjusted for the Resources' metrics.
+ * @hide
+ */
+ public Display getDefaultDisplay(Display defaultDisplay) {
+ if (mDefaultDisplay == null) {
+ if (!mCompatibilityInfo.isScalingRequired() && mCompatibilityInfo.supportsScreen()) {
+ // the app supports the display. just use the default one.
+ mDefaultDisplay = defaultDisplay;
+ } else {
+ // display needs adjustment.
+ mDefaultDisplay = Display.createMetricsBasedDisplay(
+ defaultDisplay.getDisplayId(), mMetrics);
+ }
+ }
+ return mDefaultDisplay;
+ }
+
private TypedArray getCachedStyledAttributes(int len) {
synchronized (mTmpValue) {
TypedArray attrs = mCachedStyledAttributes;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6ed1ac8..bf6003e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2692,6 +2692,12 @@
public static final String GMAIL_NUM_RETRY_UPHILL_OP = "gmail_discard_error_uphill_op";
/**
+ * Controls if the protocol buffer version of the protocol will use a multipart request for
+ * attachment uploads. Value must be an integer where non-zero means true. Defaults to 0.
+ */
+ public static final String GMAIL_USE_MULTIPART_PROTOBUF = "gmail_use_multipart_protobuf";
+
+ /**
* the transcoder URL for mobile devices.
*/
public static final String TRANSCODER_URL = "mobile_transcoder_url";
diff --git a/core/java/android/server/search/SearchDialogWrapper.java b/core/java/android/server/search/SearchDialogWrapper.java
index 67be6a6..70c7d73 100644
--- a/core/java/android/server/search/SearchDialogWrapper.java
+++ b/core/java/android/server/search/SearchDialogWrapper.java
@@ -49,7 +49,7 @@
private static final String SEARCH_UI_THREAD_NAME = "SearchDialog";
private static final int SEARCH_UI_THREAD_PRIORITY =
- android.os.Process.THREAD_PRIORITY_FOREGROUND;
+ android.os.Process.THREAD_PRIORITY_DEFAULT;
// Takes no arguments
private static final int MSG_INIT = 0;
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index a2e70b8..db9f8d852 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -113,43 +113,131 @@
/**
* Internal constants for the TTS functionality
*
- * {@hide}
*/
public class Engine {
// default values for a TTS engine when settings are not found in the provider
+ /**
+ * {@hide}
+ */
public static final int FALLBACK_TTS_DEFAULT_RATE = 100; // 1x
+ /**
+ * {@hide}
+ */
public static final int FALLBACK_TTS_DEFAULT_PITCH = 100;// 1x
+ /**
+ * {@hide}
+ */
public static final int FALLBACK_TTS_USE_DEFAULTS = 0; // false
+ /**
+ * {@hide}
+ */
public static final String FALLBACK_TTS_DEFAULT_SYNTH = "com.svox.pico";
// default values for rendering
public static final int TTS_DEFAULT_STREAM = AudioManager.STREAM_MUSIC;
// return codes for a TTS engine's check data activity
+ /**
+ * Indicates success when checking the installation status of the resources used by the
+ * text-to-speech engine with the android.intent.action.CHECK_TTS_DATA intent.
+ */
public static final int CHECK_VOICE_DATA_PASS = 1;
+ /**
+ * Indicates failure when checking the installation status of the resources used by the
+ * text-to-speech engine with the android.intent.action.CHECK_TTS_DATA intent.
+ */
public static final int CHECK_VOICE_DATA_FAIL = 0;
+ /**
+ * Indicates erroneous data when checking the installation status of the resources used by
+ * the text-to-speech engine with the android.intent.action.CHECK_TTS_DATA intent.
+ */
public static final int CHECK_VOICE_DATA_BAD_DATA = -1;
+ /**
+ * Indicates missing resources when checking the installation status of the resources used
+ * by the text-to-speech engine with the android.intent.action.CHECK_TTS_DATA intent.
+ */
public static final int CHECK_VOICE_DATA_MISSING_DATA = -2;
- public static final int CHECK_VOICE_DATA_MISSING_DATA_NO_SDCARD = -3;
+ /**
+ * Indicates missing storage volume when checking the installation status of the resources
+ * used by the text-to-speech engine with the android.intent.action.CHECK_TTS_DATA intent.
+ */
+ public static final int CHECK_VOICE_DATA_MISSING_VOLUME = -3;
// return codes for a TTS engine's check data activity
+ /**
+ * Extra information received with the android.intent.action.CHECK_TTS_DATA intent where
+ * the text-to-speech engine specifies the path to its resources.
+ */
public static final String VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
+ /**
+ * Extra information received with the android.intent.action.CHECK_TTS_DATA intent where
+ * the text-to-speech engine specifies the file names of its resources under the
+ * resource path.
+ */
public static final String VOICE_DATA_FILES = "dataFiles";
+ /**
+ * Extra information received with the android.intent.action.CHECK_TTS_DATA intent where
+ * the text-to-speech engine specifies the locale associated with each resource file.
+ */
public static final String VOICE_DATA_FILES_INFO = "dataFilesInfo";
- // keys for the parameters passed with speak commands
+ // keys for the parameters passed with speak commands. Hidden keys are used internally
+ // to maintain engine state for each TextToSpeech instance.
+ /**
+ * {@hide}
+ */
public static final String TTS_KEY_PARAM_RATE = "rate";
+ /**
+ * {@hide}
+ */
public static final String TTS_KEY_PARAM_LANGUAGE = "language";
+ /**
+ * {@hide}
+ */
public static final String TTS_KEY_PARAM_COUNTRY = "country";
+ /**
+ * {@hide}
+ */
public static final String TTS_KEY_PARAM_VARIANT = "variant";
+ /**
+ * Parameter key to specify the audio stream type to be used when speaking text
+ * or playing back a file.
+ */
public static final String TTS_KEY_PARAM_STREAM = "streamType";
+ /**
+ * Parameter key to identify an utterance in the completion listener after text has been
+ * spoken, a file has been played back or a silence duration has elapsed.
+ */
public static final String TTS_KEY_PARAM_UTTERANCE_ID = "utteranceId";
+
+ // key positions in the array of cached parameters
+ /**
+ * {@hide}
+ */
protected static final int TTS_PARAM_POSITION_RATE = 0;
+ /**
+ * {@hide}
+ */
protected static final int TTS_PARAM_POSITION_LANGUAGE = 2;
+ /**
+ * {@hide}
+ */
protected static final int TTS_PARAM_POSITION_COUNTRY = 4;
+ /**
+ * {@hide}
+ */
protected static final int TTS_PARAM_POSITION_VARIANT = 6;
+ /**
+ * {@hide}
+ */
protected static final int TTS_PARAM_POSITION_STREAM = 8;
+ /**
+ * {@hide}
+ */
protected static final int TTS_PARAM_POSITION_UTTERANCE_ID = 10;
+ /**
+ * {@hide}
+ */
protected static final int TTS_NB_CACHED_PARAMS = 6;
}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 09ebeed5..5551f64 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -117,5 +117,32 @@
private static final Object mStaticInit = new Object();
private static boolean mInitialized = false;
+
+ /**
+ * Returns a display object which uses the metric's width/height instead.
+ * @hide
+ */
+ public static Display createMetricsBasedDisplay(int displayId, DisplayMetrics metrics) {
+ return new CompatibleDisplay(displayId, metrics);
+ }
+
+ private static class CompatibleDisplay extends Display {
+ private final DisplayMetrics mMetrics;
+
+ private CompatibleDisplay(int displayId, DisplayMetrics metrics) {
+ super(displayId);
+ mMetrics = metrics;
+ }
+
+ @Override
+ public int getWidth() {
+ return mMetrics.widthPixels;
+ }
+
+ @Override
+ public int getHeight() {
+ return mMetrics.heightPixels;
+ }
+ }
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index d7457a0..576c8c1 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -358,6 +358,8 @@
private class LocalWindowManager implements WindowManager {
LocalWindowManager(WindowManager wm) {
mWindowManager = wm;
+ mDefaultDisplay = mContext.getResources().getDefaultDisplay(
+ mWindowManager.getDefaultDisplay());
}
public final void addView(View view, ViewGroup.LayoutParams params) {
@@ -420,10 +422,12 @@
}
public Display getDefaultDisplay() {
- return mWindowManager.getDefaultDisplay();
+ return mDefaultDisplay;
}
- WindowManager mWindowManager;
+ private final WindowManager mWindowManager;
+
+ private final Display mDefaultDisplay;
}
/**
diff --git a/core/java/android/webkit/GearsPermissionsManager.java b/core/java/android/webkit/GearsPermissionsManager.java
index 876f3d7..e70e449 100644
--- a/core/java/android/webkit/GearsPermissionsManager.java
+++ b/core/java/android/webkit/GearsPermissionsManager.java
@@ -55,6 +55,8 @@
// The Gears permissions db schema version table.
private final static String GEARS_SCHEMA_VERSION_TABLE_NAME =
"VersionInfo";
+ // The Gears permission value that denotes "allow access to location".
+ private static final int GEARS_ALLOW_LOCATION_ACCESS = 1;
// The shared pref name.
private static final String LAST_KNOWN_LOCATION_SETTING =
"lastKnownLocationSystemSetting";
@@ -119,8 +121,14 @@
}
private void setGearsPermissionForGoogleDomains(int systemPermission) {
- // Transform the system permission into a Gears permission
- int gearsPermission = (systemPermission == 1 ? 1 : 2);
+ // Transform the system permission into a boolean flag. When this
+ // flag is true, it means the origins in gGearsWhiteList are added
+ // to the Gears location permission table with permission 1 (allowed).
+ // When the flag is false, the origins in gGearsWhiteList are removed
+ // from the Gears location permission table. Next time the user
+ // navigates to one of these origins, she will see the normal Gears
+ // permission prompt.
+ boolean addToGearsLocationTable = (systemPermission == 1 ? true : false);
// Build the path to the Gears library.
File file = new File(mGearsPath).getParentFile();
@@ -132,6 +140,13 @@
+ GEARS_DATABASE_DIR + File.separator + GEARS_DATABASE_FILE);
// Remember whether or not we need to create the LocationAccess table.
boolean needToCreateTables = !file.exists();
+ // If the database file does not yet exist and the system location
+ // setting says that the Gears origins need to be removed from the
+ // location permission table, it means that we don't actually need
+ // to do anything at all.
+ if (needToCreateTables && !addToGearsLocationTable) {
+ return;
+ }
// Try opening the Gears database.
SQLiteDatabase permissions;
try {
@@ -177,14 +192,21 @@
schema);
}
- ContentValues permissionValues = new ContentValues();
+ if (addToGearsLocationTable) {
+ ContentValues permissionValues = new ContentValues();
- for (String url : sGearsWhiteList) {
- permissionValues.put("Name", url);
- permissionValues.put("Value", gearsPermission);
- permissions.replace(GEARS_LOCATION_ACCESS_TABLE_NAME, null,
- permissionValues);
- permissionValues.clear();
+ for (String url : sGearsWhiteList) {
+ permissionValues.put("Name", url);
+ permissionValues.put("Value", GEARS_ALLOW_LOCATION_ACCESS);
+ permissions.replace(GEARS_LOCATION_ACCESS_TABLE_NAME, null,
+ permissionValues);
+ permissionValues.clear();
+ }
+ } else {
+ for (String url : sGearsWhiteList) {
+ permissions.delete(GEARS_LOCATION_ACCESS_TABLE_NAME, "Name=?",
+ new String[] { url });
+ }
}
// Commit the transaction.
permissions.setTransactionSuccessful();
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 39360cd..474fa82 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -38,6 +38,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Vector;
import java.util.regex.Pattern;
@@ -72,7 +73,12 @@
private static final int HTTP_NOT_FOUND = 404;
private static final int HTTP_PROXY_AUTH = 407;
- private static final String CERT_MIMETYPE = "application/x-x509-ca-cert";
+ private static HashSet<String> sCertificateMimeTypeMap;
+ static {
+ sCertificateMimeTypeMap = new HashSet<String>();
+ sCertificateMimeTypeMap.add("application/x-x509-ca-cert");
+ sCertificateMimeTypeMap.add("application/x-pkcs12");
+ }
private static int sNativeLoaderCount;
@@ -318,7 +324,17 @@
if (mMimeType.equalsIgnoreCase("text/plain") ||
mMimeType.equalsIgnoreCase("application/octet-stream")) {
- String newMimeType = guessMimeTypeFromExtension();
+ // for attachment, use the filename in the Content-Disposition
+ // to guess the mimetype
+ String contentDisposition = headers.getContentDisposition();
+ String url = null;
+ if (contentDisposition != null) {
+ url = URLUtil.parseContentDisposition(contentDisposition);
+ }
+ if (url == null) {
+ url = mUrl;
+ }
+ String newMimeType = guessMimeTypeFromExtension(url);
if (newMimeType != null) {
mMimeType = newMimeType;
}
@@ -936,7 +952,7 @@
// This commits the headers without checking the response status code.
private void commitHeaders() {
- if (mIsMainPageLoader && CERT_MIMETYPE.equals(mMimeType)) {
+ if (mIsMainPageLoader && sCertificateMimeTypeMap.contains(mMimeType)) {
// In the case of downloading certificate, we will save it to the
// Keystore in commitLoad. Do not call webcore.
return;
@@ -982,7 +998,7 @@
private void commitLoad() {
if (mCancelled) return;
- if (mIsMainPageLoader && CERT_MIMETYPE.equals(mMimeType)) {
+ if (mIsMainPageLoader && sCertificateMimeTypeMap.contains(mMimeType)) {
// In the case of downloading certificate, we will save it to the
// Keystore and stop the current loading so that it will not
// generate a new history page
@@ -1409,7 +1425,7 @@
// of frames. If no content-type was specified, it is fine to
// default to text/html.
mMimeType = "text/html";
- String newMimeType = guessMimeTypeFromExtension();
+ String newMimeType = guessMimeTypeFromExtension(mUrl);
if (newMimeType != null) {
mMimeType = newMimeType;
}
@@ -1419,15 +1435,15 @@
/**
* guess MIME type based on the file extension.
*/
- private String guessMimeTypeFromExtension() {
+ private String guessMimeTypeFromExtension(String url) {
// PENDING: need to normalize url
if (WebView.LOGV_ENABLED) {
- Log.v(LOGTAG, "guessMimeTypeFromExtension: mURL = " + mUrl);
+ Log.v(LOGTAG, "guessMimeTypeFromExtension: url = " + url);
}
String mimeType =
MimeTypeMap.getSingleton().getMimeTypeFromExtension(
- MimeTypeMap.getFileExtensionFromUrl(mUrl));
+ MimeTypeMap.getFileExtensionFromUrl(url));
if (mimeType != null) {
// XXX: Until the servers send us either correct xhtml or
diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java
index 85c2275..fdbc692 100644
--- a/core/java/android/webkit/MimeTypeMap.java
+++ b/core/java/android/webkit/MimeTypeMap.java
@@ -335,6 +335,7 @@
sMimeTypeMap.loadEntry("application/x-object", "o", false);
sMimeTypeMap.loadEntry("application/x-oz-application", "oza",
false);
+ sMimeTypeMap.loadEntry("application/x-pkcs12", "p12", false);
sMimeTypeMap.loadEntry("application/x-pkcs7-certreqresp", "p7r",
false);
sMimeTypeMap.loadEntry("application/x-pkcs7-crl", "crl", false);
diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java
index d6ac3e9..9889fe9 100644
--- a/core/java/android/webkit/URLUtil.java
+++ b/core/java/android/webkit/URLUtil.java
@@ -348,7 +348,7 @@
* This header provides a filename for content that is going to be
* downloaded to the file system. We only support the attachment type.
*/
- private static String parseContentDisposition(String contentDisposition) {
+ static String parseContentDisposition(String contentDisposition) {
try {
Matcher m = CONTENT_DISPOSITION_PATTERN.matcher(contentDisposition);
if (m.find()) {
diff --git a/core/java/android/widget/Filter.java b/core/java/android/widget/Filter.java
index 7e55c78..bdecf62 100644
--- a/core/java/android/widget/Filter.java
+++ b/core/java/android/widget/Filter.java
@@ -85,7 +85,8 @@
public final void filter(CharSequence constraint, FilterListener listener) {
synchronized (mLock) {
if (mThreadHandler == null) {
- HandlerThread thread = new HandlerThread(THREAD_NAME);
+ HandlerThread thread = new HandlerThread(
+ THREAD_NAME, android.os.Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mThreadHandler = new RequestHandler(thread.getLooper());
}
diff --git a/core/res/res/values-he-rIL/donottranslate-cldr.xml b/core/res/res/values-he-rIL/donottranslate-cldr.xml
index e3feb1e..3378ed7 100644
--- a/core/res/res/values-he-rIL/donottranslate-cldr.xml
+++ b/core/res/res/values-he-rIL/donottranslate-cldr.xml
@@ -61,20 +61,20 @@
<string name="day_of_week_long_friday">יום שישי</string>
<string name="day_of_week_long_saturday">יום שבת</string>
- <string name="day_of_week_medium_sunday">יום א'</string>
- <string name="day_of_week_medium_monday">יום ב'</string>
- <string name="day_of_week_medium_tuesday">יום ג'</string>
- <string name="day_of_week_medium_wednesday">יום ד'</string>
- <string name="day_of_week_medium_thursday">יום ה'</string>
- <string name="day_of_week_medium_friday">יום ו'</string>
+ <string name="day_of_week_medium_sunday">יום א\'</string>
+ <string name="day_of_week_medium_monday">יום ב\'</string>
+ <string name="day_of_week_medium_tuesday">יום ג\'</string>
+ <string name="day_of_week_medium_wednesday">יום ד\'</string>
+ <string name="day_of_week_medium_thursday">יום ה\'</string>
+ <string name="day_of_week_medium_friday">יום ו\'</string>
<string name="day_of_week_medium_saturday">שבת</string>
- <string name="day_of_week_short_sunday">יום א'</string>
- <string name="day_of_week_short_monday">יום ב'</string>
- <string name="day_of_week_short_tuesday">יום ג'</string>
- <string name="day_of_week_short_wednesday">יום ד'</string>
- <string name="day_of_week_short_thursday">יום ה'</string>
- <string name="day_of_week_short_friday">יום ו'</string>
+ <string name="day_of_week_short_sunday">יום א\'</string>
+ <string name="day_of_week_short_monday">יום ב\'</string>
+ <string name="day_of_week_short_tuesday">יום ג\'</string>
+ <string name="day_of_week_short_wednesday">יום ד\'</string>
+ <string name="day_of_week_short_thursday">יום ה\'</string>
+ <string name="day_of_week_short_friday">יום ו\'</string>
<string name="day_of_week_short_saturday">שבת</string>
<string name="day_of_week_shortest_sunday">א</string>
diff --git a/core/res/res/values-pt-rBR/donottranslate-cldr.xml b/core/res/res/values-pt-rBR/donottranslate-cldr.xml
index 4729055..1111658 100644
--- a/core/res/res/values-pt-rBR/donottranslate-cldr.xml
+++ b/core/res/res/values-pt-rBR/donottranslate-cldr.xml
@@ -95,7 +95,7 @@
<string name="hour_minute_ampm">%-l:%M %p</string>
<string name="hour_minute_cap_ampm">%-l:%M %^p</string>
<string name="twelve_hour_time_format">h:mm a</string>
- <string name="twenty_four_hour_time_format">H'h'mm</string>
+ <string name="twenty_four_hour_time_format">H\'h\'mm</string>
<string name="numeric_date">%d/%m/%Y</string>
<string name="numeric_date_format">dd/MM/yyyy</string>
<string name="numeric_date_template">"%s/%s/%s"</string>
diff --git a/core/res/res/values-pt-rPT/donottranslate-cldr.xml b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
index f38a2d0..197cb6e 100644
--- a/core/res/res/values-pt-rPT/donottranslate-cldr.xml
+++ b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
@@ -95,7 +95,7 @@
<string name="hour_minute_ampm">%-l:%M %p</string>
<string name="hour_minute_cap_ampm">%-l:%M %^p</string>
<string name="twelve_hour_time_format">h:mm a</string>
- <string name="twenty_four_hour_time_format">H'h'mm</string>
+ <string name="twenty_four_hour_time_format">H\'h\'mm</string>
<string name="numeric_date">%d/%m/%Y</string>
<string name="numeric_date_format">dd/MM/yyyy</string>
<string name="numeric_date_template">"%s/%s/%s"</string>
diff --git a/core/res/res/values-pt/donottranslate-cldr.xml b/core/res/res/values-pt/donottranslate-cldr.xml
index 4729055..1111658 100644
--- a/core/res/res/values-pt/donottranslate-cldr.xml
+++ b/core/res/res/values-pt/donottranslate-cldr.xml
@@ -95,7 +95,7 @@
<string name="hour_minute_ampm">%-l:%M %p</string>
<string name="hour_minute_cap_ampm">%-l:%M %^p</string>
<string name="twelve_hour_time_format">h:mm a</string>
- <string name="twenty_four_hour_time_format">H'h'mm</string>
+ <string name="twenty_four_hour_time_format">H\'h\'mm</string>
<string name="numeric_date">%d/%m/%Y</string>
<string name="numeric_date_format">dd/MM/yyyy</string>
<string name="numeric_date_template">"%s/%s/%s"</string>
diff --git a/core/res/res/values-vi-rVN/donottranslate-cldr.xml b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
index 72ff8b6..6f2d342 100644
--- a/core/res/res/values-vi-rVN/donottranslate-cldr.xml
+++ b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
@@ -133,8 +133,8 @@
<string name="same_month_md1_time1_md2_time2">%3$s %2$s %5$s - %8$s %7$s %10$s</string>
<string name="same_year_wday1_md1_time1_wday2_md2_time2">%1$s %3$s %2$s %5$s - %6$s %8$s %7$s %10$s</string>
<string name="same_month_wday1_md1_time1_wday2_md2_time2">%1$s %3$s %2$s %5$s - %6$s %8$s %7$s %10$s</string>
- <string name="same_year_mdy1_time1_mdy2_time2">Ngày %3$s tháng %2$s năm %4$s %5$s - 'Ngày %8$s tháng %7$s năm %9$s %10$s</string>
- <string name="same_month_mdy1_time1_mdy2_time2">Ngày %3$s tháng %2$s năm %4$s %5$s - 'Ngày %8$s tháng %7$s năm %9$s %10$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">Ngày %3$s tháng %2$s năm %4$s %5$s - \'Ngày %8$s tháng %7$s năm %9$s %10$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">Ngày %3$s tháng %2$s năm %4$s %5$s - \'Ngày %8$s tháng %7$s năm %9$s %10$s</string>
<string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %3$s %2$s %4$s %5$s - %6$s, %8$s %7$s %9$s %10$s</string>
<string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %3$s %2$s %4$s %5$s - %6$s, %8$s %7$s %9$s %10$s</string>
<string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s %4$s - %6$s, %8$s %7$s %9$s</string>
diff --git a/data/sounds/AudioPackage2.mk b/data/sounds/AudioPackage2.mk
index aea3f0b..649787e 100644
--- a/data/sounds/AudioPackage2.mk
+++ b/data/sounds/AudioPackage2.mk
@@ -23,7 +23,7 @@
$(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
$(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
$(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \
- $(LOCAL_PATH)/Silence.ogg:system/media/audio/ringtones/Silence.ogg \
+ $(LOCAL_PATH)/Silence.ogg:system/media/audio/ringtones/notifications/Silence.ogg \
$(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \
$(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \
$(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \
diff --git a/data/sounds/OriginalAudio.mk b/data/sounds/OriginalAudio.mk
index 8c8fc32..fc1e921 100644
--- a/data/sounds/OriginalAudio.mk
+++ b/data/sounds/OriginalAudio.mk
@@ -22,7 +22,7 @@
$(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
$(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
$(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \
- $(LOCAL_PATH)/Silence.ogg:system/media/audio/ringtones/Silence.ogg \
+ $(LOCAL_PATH)/Silence.ogg:system/media/audio/ringtones/notifications/Silence.ogg \
$(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \
$(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \
$(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index 4247483..64cdb5b 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -84,6 +84,7 @@
mNbChannels = DEFAULT_TTS_NB_CHANNELS;
mBufferSize = DEFAULT_TTS_BUFFERSIZE;
mBuffer = new int8_t[mBufferSize];
+ memset(mBuffer, 0, mBufferSize);
}
~SynthProxyJniStorage() {
@@ -194,6 +195,7 @@
prepAudioTrack(pJniData, pForAfter->streamType, rate, format, channel);
if (pJniData->mAudioOut) {
pJniData->mAudioOut->write(wav, bufferSize);
+ memset(wav, 0, bufferSize);
//LOGV("AudioTrack wrote: %d bytes", bufferSize);
} else {
LOGE("Can't play, null audiotrack");
@@ -208,6 +210,7 @@
}
if (bufferSize > 0){
fwrite(wav, 1, bufferSize, pForAfter->outputFile);
+ memset(wav, 0, bufferSize);
}
}
// Future update:
@@ -473,6 +476,7 @@
unsigned int unique_identifier;
+ memset(pSynthData->mBuffer, 0, pSynthData->mBufferSize);
result = pSynthData->mNativeSynthInterface->synthesizeText(textNativeString,
pSynthData->mBuffer, pSynthData->mBufferSize, (void *)pForAfter);
@@ -554,6 +558,7 @@
if (pSynthData->mNativeSynthInterface) {
const char *textNativeString = env->GetStringUTFChars(textJavaString, 0);
+ memset(pSynthData->mBuffer, 0, pSynthData->mBufferSize);
result = pSynthData->mNativeSynthInterface->synthesizeText(textNativeString,
pSynthData->mBuffer, pSynthData->mBufferSize, (void *)pForAfter);
env->ReleaseStringUTFChars(textJavaString, textNativeString);
@@ -575,12 +580,12 @@
SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- if (pSynthData->mNativeSynthInterface) {
- result = pSynthData->mNativeSynthInterface->stop();
- }
if (pSynthData->mAudioOut) {
pSynthData->mAudioOut->stop();
}
+ if (pSynthData->mNativeSynthInterface) {
+ result = pSynthData->mNativeSynthInterface->stop();
+ }
return result;
}
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index 4d25183..7c4996e 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -340,6 +340,8 @@
Log.i("TTS service received", text);
if (queueMode == TextToSpeech.TTS_QUEUE_FLUSH) {
stop(callingApp);
+ } else if (queueMode == 2) {
+ stopAll(callingApp);
}
mSpeechQueue.add(new SpeechItem(callingApp, text, params, SpeechItem.TEXT));
if (!mIsSpeaking) {
@@ -364,6 +366,8 @@
ArrayList<String> params) {
if (queueMode == TextToSpeech.TTS_QUEUE_FLUSH) {
stop(callingApp);
+ } else if (queueMode == 2) {
+ stopAll(callingApp);
}
mSpeechQueue.add(new SpeechItem(callingApp, earcon, params, SpeechItem.EARCON));
if (!mIsSpeaking) {
@@ -373,7 +377,7 @@
}
/**
- * Stops all speech output and removes any utterances still in the queue.
+ * Stops all speech output and removes any utterances still in the queue for the calling app.
*/
private int stop(String callingApp) {
int result = TextToSpeech.TTS_ERROR;
@@ -389,15 +393,20 @@
mSpeechQueue.remove(i);
}
}
-
- result = nativeSynth.stop();
- mIsSpeaking = false;
- if (mPlayer != null) {
- try {
- mPlayer.stop();
- } catch (IllegalStateException e) {
- // Do nothing, the player is already stopped.
+ if ((mCurrentSpeechItem != null) &&
+ mCurrentSpeechItem.mCallingApp.equals(callingApp)) {
+ result = nativeSynth.stop();
+ if (mPlayer != null) {
+ try {
+ mPlayer.stop();
+ } catch (IllegalStateException e) {
+ // Do nothing, the player is already stopped.
+ }
}
+ mIsSpeaking = false;
+ mCurrentSpeechItem = null;
+ } else {
+ result = TextToSpeech.TTS_SUCCESS;
}
Log.i("TTS", "Stopped");
}
@@ -407,7 +416,55 @@
} finally {
// This check is needed because finally will always run; even if the
// method returns somewhere in the try block.
- mCurrentSpeechItem = null;
+ if (speechQueueAvailable) {
+ speechQueueLock.unlock();
+ }
+ return result;
+ }
+ }
+
+
+
+ /**
+ * Stops all speech output and removes any utterances still in the queue globally.
+ */
+ private int stopAll(String callingApp) {
+ int result = TextToSpeech.TTS_ERROR;
+ boolean speechQueueAvailable = false;
+ try{
+ // If the queue is locked for more than 1 second,
+ // something has gone very wrong with processSpeechQueue.
+ speechQueueAvailable = speechQueueLock.tryLock(1000, TimeUnit.MILLISECONDS);
+ if (speechQueueAvailable) {
+ for (int i = mSpeechQueue.size() - 1; i > -1; i--){
+ if (mSpeechQueue.get(i).mType != SpeechItem.TEXT_TO_FILE){
+ mSpeechQueue.remove(i);
+ }
+ }
+ if ((mCurrentSpeechItem != null) &&
+ ((mCurrentSpeechItem.mType != SpeechItem.TEXT_TO_FILE) ||
+ mCurrentSpeechItem.mCallingApp.equals(callingApp))) {
+ result = nativeSynth.stop();
+ if (mPlayer != null) {
+ try {
+ mPlayer.stop();
+ } catch (IllegalStateException e) {
+ // Do nothing, the player is already stopped.
+ }
+ }
+ mIsSpeaking = false;
+ mCurrentSpeechItem = null;
+ } else {
+ result = TextToSpeech.TTS_SUCCESS;
+ }
+ Log.i("TTS", "Stopped all");
+ }
+ } catch (InterruptedException e) {
+ Log.e("TTS stopAll", "tryLock interrupted");
+ e.printStackTrace();
+ } finally {
+ // This check is needed because finally will always run; even if the
+ // method returns somewhere in the try block.
if (speechQueueAvailable) {
speechQueueLock.unlock();
}
@@ -430,7 +487,6 @@
if (utteranceId.length() > 0){
dispatchUtteranceCompletedCallback(utteranceId, callingApp);
}
- mCurrentSpeechItem = null;
processSpeechQueue();
}
@@ -466,7 +522,6 @@
if (utteranceId.length() > 0){
dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp);
}
- mCurrentSpeechItem = null;
processSpeechQueue();
}
}
@@ -531,13 +586,12 @@
// This check is needed because finally will always run;
// even if the
// method returns somewhere in the try block.
- if (synthAvailable) {
- synthesizerLock.unlock();
- }
if (utteranceId.length() > 0){
dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp);
}
- mCurrentSpeechItem = null;
+ if (synthAvailable) {
+ synthesizerLock.unlock();
+ }
processSpeechQueue();
}
}
@@ -595,13 +649,12 @@
// This check is needed because finally will always run;
// even if the
// method returns somewhere in the try block.
- if (synthAvailable) {
- synthesizerLock.unlock();
- }
if (utteranceId.length() > 0){
dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp);
}
- mCurrentSpeechItem = null;
+ if (synthAvailable) {
+ synthesizerLock.unlock();
+ }
processSpeechQueue();
}
}
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 131e156..78db6f9 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -68,6 +68,7 @@
private static final String SETTINGS_FILENAME = "appwidgets.xml";
private static final String SETTINGS_TMP_FILENAME = SETTINGS_FILENAME + ".tmp";
+ private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
/*
* When identifying a Host or Provider based on the calling process, use the uid field.
@@ -629,9 +630,12 @@
Binder.restoreCallingIdentity(token);
}
if (!alreadyRegistered) {
+ long period = p.info.updatePeriodMillis;
+ if (period < MIN_UPDATE_PERIOD) {
+ period = MIN_UPDATE_PERIOD;
+ }
mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + p.info.updatePeriodMillis,
- p.info.updatePeriodMillis, p.broadcast);
+ SystemClock.elapsedRealtime() + period, period, p.broadcast);
}
}
}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 01394ad..b4754b6 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -192,6 +192,7 @@
WifiService(Context context, WifiStateTracker tracker) {
mContext = context;
mWifiStateTracker = tracker;
+ mWifiStateTracker.enableRssiPolling(true);
mBatteryStats = BatteryStatsService.getService();
/*
@@ -1560,9 +1561,11 @@
mAlarmManager.cancel(mIdleIntent);
mDeviceIdle = false;
mScreenOff = false;
+ mWifiStateTracker.enableRssiPolling(true);
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Log.d(TAG, "ACTION_SCREEN_OFF");
mScreenOff = true;
+ mWifiStateTracker.enableRssiPolling(false);
/*
* Set a timer to put Wi-Fi to sleep, but only if the screen is off
* AND the "stay on while plugged in" setting doesn't match the
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SearchablesTest.java b/tests/AndroidTests/src/com/android/unit_tests/SearchablesTest.java
index ecc8dfe..4e5f7a9 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/SearchablesTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/SearchablesTest.java
@@ -93,8 +93,8 @@
Context appContext = si.getActivityContext(mContext);
assertNotNull(appContext);
MoreAsserts.assertNotEqual(appContext, mContext);
- assertEquals("Android Search", appContext.getString(si.getHintId()));
- assertEquals("Google", appContext.getString(si.getLabelId()));
+ assertEquals("Quick Search Box", appContext.getString(si.getHintId()));
+ assertEquals("Quick Search Box", appContext.getString(si.getLabelId()));
}
/**
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 63687b3..3aa31bf 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -239,6 +239,7 @@
private boolean mIsScanModeActive;
private boolean mIsScanModeSetDueToAHiddenNetwork;
+ private boolean mEnableRssiPolling;
// Wi-Fi run states:
private static final int RUN_STATE_STARTING = 1;
@@ -338,6 +339,7 @@
private void setSupplicantState(SupplicantState state) {
mWifiInfo.setSupplicantState(state);
updateNetworkInfo();
+ checkPollTimer();
}
public SupplicantState getSupplicantState() {
@@ -352,6 +354,7 @@
private void setSupplicantState(String stateName) {
mWifiInfo.setSupplicantState(stateName);
updateNetworkInfo();
+ checkPollTimer();
}
/**
@@ -540,8 +543,10 @@
* Set the interval timer for polling connection information
* that is not delivered asynchronously.
*/
- private synchronized void setPollTimer () {
- if (!hasMessages(EVENT_POLL_INTERVAL)) {
+ private synchronized void checkPollTimer() {
+ if (mEnableRssiPolling &&
+ mWifiInfo.getSupplicantState() == SupplicantState.COMPLETED &&
+ !hasMessages(EVENT_POLL_INTERVAL)) {
sendEmptyMessageDelayed(EVENT_POLL_INTERVAL, POLL_STATUS_INTERVAL_MSECS);
}
}
@@ -637,6 +642,13 @@
setBluetoothScanMode(isBluetoothPlaying);
}
+ public void enableRssiPolling(boolean enable) {
+ if (mEnableRssiPolling != enable) {
+ mEnableRssiPolling = enable;
+ checkPollTimer();
+ }
+ }
+
@Override
public void releaseWakeLock() {
if (mReleaseWakeLockCallback != null) {
@@ -1022,9 +1034,7 @@
case EVENT_POLL_INTERVAL:
if (mWifiInfo.getSupplicantState() != SupplicantState.UNINITIALIZED) {
requestPolledInfo(mWifiInfo);
- if (mWifiInfo.getSupplicantState() == SupplicantState.COMPLETED) {
- setPollTimer();
- }
+ checkPollTimer();
}
break;
@@ -1163,7 +1173,7 @@
}
private void configureInterface() {
- setPollTimer();
+ checkPollTimer();
mLastSignalLevel = -1;
if (!mUseStaticIp) {
if (!mHaveIpAddress && !mObtainingIpAddress) {