Merge change 5015

* changes:
  Cleanup includes so Log.h can use the tag.  rsUtils.h is the file that should be included everywhere and contain rs global defines.
diff --git a/api/current.xml b/api/current.xml
index 202a1d4..55066f1 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -683,6 +683,17 @@
  visibility="public"
 >
 </field>
+<field name="READ_HISTORY_BOOKMARKS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.READ_HISTORY_BOOKMARKS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="READ_INPUT_STATE"
  type="java.lang.String"
  transient="false"
@@ -1134,6 +1145,17 @@
  visibility="public"
 >
 </field>
+<field name="WRITE_HISTORY_BOOKMARKS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.WRITE_HISTORY_BOOKMARKS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="WRITE_OWNER_DATA"
  type="java.lang.String"
  transient="false"
@@ -30535,6 +30557,17 @@
  visibility="public"
 >
 </method>
+<method name="getApplicationInfo"
+ return="android.content.pm.ApplicationInfo"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getAssets"
  return="android.content.res.AssetManager"
  abstract="true"
@@ -31898,6 +31931,17 @@
  visibility="public"
 >
 </method>
+<method name="getApplicationInfo"
+ return="android.content.pm.ApplicationInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getAssets"
  return="android.content.res.AssetManager"
  abstract="false"
@@ -35082,6 +35126,17 @@
  visibility="public"
 >
 </field>
+<field name="ACTION_POWER_USAGE_SUMMARY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.POWER_USAGE_SUMMARY&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ACTION_PROVIDER_CHANGED"
  type="java.lang.String"
  transient="false"
@@ -35192,6 +35247,17 @@
  visibility="public"
 >
 </field>
+<field name="ACTION_SEND_MULTIPLE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.SEND_MULTIPLE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ACTION_SET_WALLPAPER"
  type="java.lang.String"
  transient="false"
@@ -38550,6 +38616,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_SUPPORTS_LARGE_SCREENS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="512"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_SYSTEM"
  type="int"
  transient="false"
@@ -38623,16 +38700,6 @@
  visibility="public"
 >
 </field>
-<field name="expandable"
- type="boolean"
- transient="false"
- volatile="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="flags"
  type="int"
  transient="false"
@@ -40505,17 +40572,6 @@
  visibility="public"
 >
 </field>
-<field name="GET_EXPANDABLE"
- type="int"
- transient="false"
- volatile="false"
- value="131072"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="GET_GIDS"
  type="int"
  transient="false"
@@ -50444,6 +50500,17 @@
  visibility="public"
 >
 </method>
+<method name="prepareToDraw"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="recycle"
  return="void"
  abstract="false"
@@ -109330,6 +109397,17 @@
  visibility="public"
 >
 </field>
+<field name="TTS_DEFAULT_COUNTRY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;tts_default_country&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TTS_DEFAULT_LANG"
  type="java.lang.String"
  transient="false"
@@ -109374,6 +109452,17 @@
  visibility="public"
 >
 </field>
+<field name="TTS_DEFAULT_VARIANT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;tts_default_variant&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TTS_USE_DEFAULTS"
  type="java.lang.String"
  transient="false"
@@ -117907,6 +117996,17 @@
  visibility="public"
 >
 </method>
+<method name="getApplicationInfo"
+ return="android.content.pm.ApplicationInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getAssets"
  return="android.content.res.AssetManager"
  abstract="false"
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 81639ad..980ce78 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -42,6 +42,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <pthread.h>
+#include <signal.h>
 }
 
 // When you enable this, as well as DEBUG_REFS=1 and
@@ -63,6 +64,10 @@
 static int debug_frame_cnt;
 #endif
 
+static int getCallingPid() {
+    return IPCThreadState::self()->getCallingPid();
+}
+
 // ----------------------------------------------------------------------------
 
 void CameraService::instantiate() {
@@ -87,7 +92,9 @@
 
 sp<ICamera> CameraService::connect(const sp<ICameraClient>& cameraClient)
 {
-    LOGD("Connect E from ICameraClient %p", cameraClient->asBinder().get());
+    int callingPid = getCallingPid();
+    LOGD("CameraService::connect E (pid %d, client %p)", callingPid,
+            cameraClient->asBinder().get());
 
     Mutex::Autolock lock(mLock);
     sp<Client> client;
@@ -96,36 +103,46 @@
         if (currentClient != 0) {
             sp<ICameraClient> currentCameraClient(currentClient->getCameraClient());
             if (cameraClient->asBinder() == currentCameraClient->asBinder()) {
-                // this is the same client reconnecting...
-                LOGD("Connect X same client (%p) is reconnecting...", cameraClient->asBinder().get());
+                // This is the same client reconnecting...
+                LOGD("CameraService::connect X (pid %d, same client %p) is reconnecting...",
+                    callingPid, cameraClient->asBinder().get());
                 return currentClient;
             } else {
-                // it's another client... reject it
-                LOGD("new client (%p) attempting to connect - rejected", cameraClient->asBinder().get());
+                // It's another client... reject it
+                LOGD("CameraService::connect X (pid %d, new client %p) rejected. "
+                    "(old pid %d, old client %p)",
+                    callingPid, cameraClient->asBinder().get(),
+                    currentClient->mClientPid, currentCameraClient->asBinder().get());
+                if (kill(currentClient->mClientPid, 0) == ESRCH) {
+                    LOGD("The old client is dead!");
+                }
                 return client;
             }
         } else {
             // can't promote, the previous client has died...
-            LOGD("new client connecting, old reference was dangling...");
+            LOGD("New client (pid %d) connecting, old reference was dangling...",
+                    callingPid);
             mClient.clear();
         }
     }
 
     // create a new Client object
-    client = new Client(this, cameraClient, IPCThreadState::self()->getCallingPid());
+    client = new Client(this, cameraClient, callingPid);
     mClient = client;
 #if DEBUG_CLIENT_REFERENCES
     // Enable tracking for this object, and track increments and decrements of
     // the refcount.
     client->trackMe(true, true);
 #endif
-    LOGD("Connect X");
+    LOGD("CameraService::connect X");
     return client;
 }
 
 void CameraService::removeClient(const sp<ICameraClient>& cameraClient)
 {
-    // declar this outside the lock to make absolutely sure the
+    int callingPid = getCallingPid();
+
+    // Declare this outside the lock to make absolutely sure the
     // destructor won't be called with the lock held.
     sp<Client> client;
 
@@ -133,26 +150,28 @@
 
     if (mClient == 0) {
         // This happens when we have already disconnected.
-        LOGV("mClient is null.");
+        LOGD("removeClient (pid %d): already disconnected", callingPid);
         return;
     }
 
-    // Promote mClient. It should never fail because we're called from
-    // a binder call, so someone has to have a strong reference.
+    // Promote mClient. It can fail if we are called from this path:
+    // Client::~Client() -> disconnect() -> removeClient().
     client = mClient.promote();
     if (client == 0) {
-        LOGW("can't get a strong reference on mClient!");
+        LOGD("removeClient (pid %d): no more strong reference", callingPid);
         mClient.clear();
         return;
     }
 
     if (cameraClient->asBinder() != client->getCameraClient()->asBinder()) {
         // ugh! that's not our client!!
-        LOGW("removeClient() called, but mClient doesn't match!");
+        LOGW("removeClient (pid %d): mClient doesn't match!", callingPid);
     } else {
         // okay, good, forget about mClient
         mClient.clear();
     }
+
+    LOGD("removeClient (pid %d) done", callingPid);
 }
 
 static sp<MediaPlayer> newMediaPlayer(const char *file) 
@@ -177,7 +196,8 @@
 CameraService::Client::Client(const sp<CameraService>& cameraService,
         const sp<ICameraClient>& cameraClient, pid_t clientPid)
 {
-    LOGD("Client E constructor");
+    int callingPid = getCallingPid();
+    LOGD("Client::Client E (pid %d)", callingPid);
     mCameraService = cameraService;
     mCameraClient = cameraClient;
     mClientPid = clientPid;
@@ -189,22 +209,27 @@
 
     // Callback is disabled by default
     mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
-    LOGD("Client X constructor");
+    LOGD("Client::Client X (pid %d)", callingPid);
 }
 
 status_t CameraService::Client::checkPid()
 {
-    if (mClientPid == IPCThreadState::self()->getCallingPid()) return NO_ERROR;
-    LOGW("Attempt to use locked camera (%p) from different process", getCameraClient()->asBinder().get());
+    int callingPid = getCallingPid();
+    if (mClientPid == callingPid) return NO_ERROR;
+    LOGW("Attempt to use locked camera (client %p) from different process "
+        " (old pid %d, new pid %d)",
+        getCameraClient()->asBinder().get(), mClientPid, callingPid);
     return -EBUSY;
 }
 
 status_t CameraService::Client::lock()
 {
+    int callingPid = getCallingPid();
+    LOGD("lock from pid %d (mClientPid %d)", callingPid, mClientPid);
     Mutex::Autolock _l(mLock);
     // lock camera to this client if the the camera is unlocked
     if (mClientPid == 0) {
-        mClientPid = IPCThreadState::self()->getCallingPid();
+        mClientPid = callingPid;
         return NO_ERROR;
     }
     // returns NO_ERROR if the client already owns the camera, -EBUSY otherwise
@@ -213,13 +238,14 @@
 
 status_t CameraService::Client::unlock()
 {
+    int callingPid = getCallingPid();
+    LOGD("unlock from pid %d (mClientPid %d)", callingPid, mClientPid);    
     Mutex::Autolock _l(mLock);
     // allow anyone to use camera
-    LOGD("unlock (%p)", getCameraClient()->asBinder().get());
     status_t result = checkPid();
     if (result == NO_ERROR) {
         mClientPid = 0;
-
+        LOGD("clear mCameraClient (pid %d)", callingPid);
         // we need to remove the reference so that when app goes
         // away, the reference count goes to 0.
         mCameraClient.clear();
@@ -229,15 +255,17 @@
 
 status_t CameraService::Client::connect(const sp<ICameraClient>& client)
 {
+    int callingPid = getCallingPid();
+
     // connect a new process to the camera
-    LOGD("connect (%p)", client->asBinder().get());
+    LOGD("Client::connect E (pid %d, client %p)", callingPid, client->asBinder().get());
 
     // I hate this hack, but things get really ugly when the media recorder
     // service is handing back the camera to the app. The ICameraClient
     // destructor will be called during the same IPC, making it look like
     // the remote client is trying to disconnect. This hack temporarily
     // sets the mClientPid to an invalid pid to prevent the hardware from
-    //  being torn down.
+    // being torn down.
     {
 
         // hold a reference to the old client or we will deadlock if the client is
@@ -246,24 +274,29 @@
         {
             Mutex::Autolock _l(mLock);
             if (mClientPid != 0 && checkPid() != NO_ERROR) {
-                LOGW("Tried to connect to locked camera");
+                LOGW("Tried to connect to locked camera (old pid %d, new pid %d)",
+                        mClientPid, callingPid);
                 return -EBUSY;
             }
             oldClient = mCameraClient;
 
             // did the client actually change?
-            if (client->asBinder() == mCameraClient->asBinder()) return NO_ERROR;
+            if (client->asBinder() == mCameraClient->asBinder()) {
+                LOGD("Connect to the same client");
+                return NO_ERROR;
+            }
 
             mCameraClient = client;
             mClientPid = -1;
             mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
-            LOGD("connect new process (%d) to existing camera client", mClientPid);
+            LOGD("Connect to the new client (pid %d, client %p)",
+                callingPid, mCameraClient->asBinder().get());
         }
 
     }
     // the old client destructor is called when oldClient goes out of scope
     // now we set the new PID to lock the interface again
-    mClientPid = IPCThreadState::self()->getCallingPid();
+    mClientPid = callingPid;
 
     return NO_ERROR;
 }
@@ -280,8 +313,11 @@
 
 CameraService::Client::~Client()
 {
+    int callingPid = getCallingPid();
+
     // tear down client
-    LOGD("Client (%p)  E destructor", getCameraClient()->asBinder().get());
+    LOGD("Client::~Client E (pid %d, client %p)",
+            callingPid, getCameraClient()->asBinder().get());
     if (mSurface != 0 && !mUseOverlay) {
 #if HAVE_ANDROID_OS
         pthread_t thr;
@@ -307,19 +343,21 @@
     }
 
     // make sure we tear down the hardware
-    mClientPid = IPCThreadState::self()->getCallingPid();
+    mClientPid = callingPid;
     disconnect();
-    LOGD("Client X destructor");
+    LOGD("Client::~Client X (pid %d)", mClientPid);
 }
 
 void CameraService::Client::disconnect()
 {
-    LOGD("Client (%p) E disconnect from (%d)",
-            getCameraClient()->asBinder().get(),
-            IPCThreadState::self()->getCallingPid());
+    int callingPid = getCallingPid();    
+
+    LOGD("Client::disconnect() E (pid %d client %p)",
+            callingPid, getCameraClient()->asBinder().get());
+
     Mutex::Autolock lock(mLock);
     if (mClientPid <= 0) {
-        LOGD("camera is unlocked, don't tear down hardware");
+        LOGD("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
         return;
     }
     if (checkPid() != NO_ERROR) {
@@ -339,13 +377,13 @@
         mHardware->release();
     }
     mHardware.clear();
-    LOGD("Client X disconnect");
+    LOGD("Client::disconnect() X (pid %d)", callingPid);
 }
 
 // pass the buffered ISurface to the camera service
 status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface)
 {
-    LOGD("setPreviewDisplay(%p)", surface.get());
+    LOGD("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());
     Mutex::Autolock lock(mLock);
     status_t result = checkPid();
     if (result != NO_ERROR) return result;
@@ -365,7 +403,7 @@
 // preview are handled.
 void CameraService::Client::setPreviewCallbackFlag(int callback_flag)
 {
-    LOGV("setPreviewCallbackFlag");
+    LOGV("setPreviewCallbackFlag (pid %d)", getCallingPid());
     Mutex::Autolock lock(mLock);
     if (checkPid() != NO_ERROR) return;
     mPreviewCallbackFlag = callback_flag;
@@ -374,7 +412,9 @@
 // start preview mode, must call setPreviewDisplay first
 status_t CameraService::Client::startCameraMode(camera_mode mode)
 {
-    LOGD("startCameraMode(%d)", mode);
+    int callingPid = getCallingPid();
+
+    LOGD("startCameraMode(%d) (pid %d)", mode, callingPid);
 
     /* we cannot call into mHardware with mLock held because
      * mHardware has callbacks onto us which acquire this lock
@@ -405,7 +445,7 @@
 
 status_t CameraService::Client::startRecordingMode()
 {
-    LOGV("startRecordingMode");
+    LOGD("startRecordingMode (pid %d)", getCallingPid());
 
     status_t ret = UNKNOWN_ERROR;
 
@@ -433,7 +473,7 @@
 
 status_t CameraService::Client::startPreviewMode()
 {
-    LOGV("startPreviewMode");
+    LOGD("startPreviewMode (pid %d)", getCallingPid());
 
     // if preview has been enabled, nothing needs to be done
     if (mHardware->previewEnabled()) {
@@ -500,11 +540,15 @@
 
 status_t CameraService::Client::startPreview()
 {
+    LOGD("startPreview (pid %d)", getCallingPid());
+    
     return startCameraMode(CAMERA_PREVIEW_MODE);
 }
 
 status_t CameraService::Client::startRecording()
 {
+    LOGD("startRecording (pid %d)", getCallingPid());
+
     if (mMediaPlayerBeep.get() != NULL) {
         mMediaPlayerBeep->seekTo(0);
         mMediaPlayerBeep->start();
@@ -515,7 +559,7 @@
 // stop preview mode
 void CameraService::Client::stopPreview()
 {
-    LOGD("stopPreview()");
+    LOGD("stopPreview (pid %d)", getCallingPid());
 
     Mutex::Autolock lock(mLock);
     if (checkPid() != NO_ERROR) return;
@@ -537,7 +581,7 @@
 // stop recording mode
 void CameraService::Client::stopRecording()
 {
-    LOGV("stopRecording()");
+    LOGD("stopRecording (pid %d)", getCallingPid());
 
     Mutex::Autolock lock(mLock);
     if (checkPid() != NO_ERROR) return;
@@ -552,15 +596,13 @@
         mMediaPlayerBeep->start();
     }
     mHardware->stopRecording();
-    LOGV("stopRecording(), hardware stopped OK");
+    LOGD("stopRecording(), hardware stopped OK");
     mPreviewBuffer.clear();
 }
 
 // release a recording frame
 void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem)
 {
-    LOGV("releaseRecordingFrame()");
-
     Mutex::Autolock lock(mLock);
     if (checkPid() != NO_ERROR) return;
 
@@ -704,7 +746,7 @@
 // take a picture - image is returned in callback
 status_t CameraService::Client::autoFocus()
 {
-    LOGV("autoFocus");
+    LOGD("autoFocus (pid %d)", getCallingPid());
 
     Mutex::Autolock lock(mLock);
     status_t result = checkPid();
@@ -722,7 +764,7 @@
 // take a picture - image is returned in callback
 status_t CameraService::Client::takePicture()
 {
-    LOGD("takePicture");
+    LOGD("takePicture (pid %d)", getCallingPid());
 
     Mutex::Autolock lock(mLock);
     status_t result = checkPid();
@@ -920,6 +962,7 @@
 
 void CameraService::Client::postShutter()
 {
+    LOGD("postShutter");
     mCameraClient->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
 }
 
@@ -1029,7 +1072,7 @@
     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
         snprintf(buffer, SIZE, "Permission Denial: "
                 "can't dump CameraService from pid=%d, uid=%d\n",
-                IPCThreadState::self()->getCallingPid(),
+                getCallingPid(),
                 IPCThreadState::self()->getCallingUid());
         result.append(buffer);
         write(fd, result.string(), result.size());
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 3af80fa..841e3df 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -80,6 +80,14 @@
             doRestore();
             return;
         }
+
+        if ("transport".equals(op)) {
+            doTransport();
+            return;
+        }
+
+        System.err.println("Unknown command");
+        showUsage();
     }
 
     private void doRun() {
@@ -113,6 +121,19 @@
         }
     }
 
+    private void doTransport() {
+        try {
+            int which = Integer.parseInt(nextArg());
+            int old = mBmgr.selectBackupTransport(which);
+            System.out.println("Selected transport " + which + " (formerly " + old + ")");
+        } catch (NumberFormatException e) {
+            showUsage();
+        } catch (RemoteException e) {
+            System.err.println(e.toString());
+            System.err.println(BMGR_NOT_RUNNING_ERR);
+        }
+    }
+
     private void doList() {
         String arg = nextArg();     // sets, transports, packages set#
         if ("transports".equals(arg)) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 51a8ed2..ca9632a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -864,7 +864,9 @@
             final Integer dialogId = ids[i];
             Bundle dialogState = b.getBundle(savedDialogKeyFor(dialogId));
             if (dialogState != null) {
-                final Dialog dialog = createDialog(dialogId);
+                // Calling onRestoreInstanceState() below will invoke dispatchOnCreate
+                // so tell createDialog() not to do it, otherwise we get an exception
+                final Dialog dialog = createDialog(dialogId, false);
                 mManagedDialogs.put(dialogId, dialog);
                 onPrepareDialog(dialogId, dialog);
                 dialog.onRestoreInstanceState(dialogState);
@@ -872,13 +874,13 @@
         }
     }
 
-    private Dialog createDialog(Integer dialogId) {
+    private Dialog createDialog(Integer dialogId, boolean dispatchOnCreate) {
         final Dialog dialog = onCreateDialog(dialogId);
         if (dialog == null) {
             throw new IllegalArgumentException("Activity#onCreateDialog did "
                     + "not create a dialog for id " + dialogId);
         }
-        dialog.dispatchOnCreate(null);
+        if (dispatchOnCreate) dialog.dispatchOnCreate(null);
         return dialog;
     }
 
@@ -2430,7 +2432,7 @@
         }
         Dialog dialog = mManagedDialogs.get(id);
         if (dialog == null) {
-            dialog = createDialog(id);
+            dialog = createDialog(id, true);
             mManagedDialogs.put(id, dialog);
         }
         
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 477badb..98bd45a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -187,7 +187,7 @@
             try {
                 appInfo = getPackageManager().getApplicationInfo(
                         pkgInfo.getPackageName(),
-                        PackageManager.GET_SUPPORTS_DENSITIES | PackageManager.GET_EXPANDABLE);
+                        PackageManager.GET_SUPPORTS_DENSITIES);
             } catch (RemoteException e) {
                 throw new AssertionError(e);
             }
@@ -287,6 +287,10 @@
             return mPackageName;
         }
 
+        public ApplicationInfo getApplicationInfo() {
+            return mApplicationInfo;
+        }
+        
         public boolean isSecurityViolation() {
             return mSecurityViolation;
         }
@@ -2084,6 +2088,10 @@
         return mInitialApplication;
     }
     
+    public String getProcessName() {
+        return mBoundApplication.processName;
+    }
+    
     public ApplicationContext getSystemContext() {
         synchronized (this) {
             if (mSystemContext == null) {
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index d08be86..8ec1445 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -286,6 +286,14 @@
     }
 
     @Override
+    public ApplicationInfo getApplicationInfo() {
+        if (mPackageInfo != null) {
+            return mPackageInfo.getApplicationInfo();
+        }
+        throw new RuntimeException("Not supported in system context");
+    }
+
+    @Override
     public String getPackageResourcePath() {
         if (mPackageInfo != null) {
             return mPackageInfo.getResDir();
@@ -1045,11 +1053,6 @@
     }
 
     private SearchManager getSearchManager() {
-        // This is only useable in Activity Contexts
-        if (getActivityToken() == null) {
-            throw new AndroidRuntimeException(
-                "Acquiring SearchManager objects only valid in Activity Contexts.");
-        }
         synchronized (mSync) {
             if (mSearchManager == null) {
                 mSearchManager = new SearchManager(getOuterContext(), mMainThread.getHandler());
@@ -2366,22 +2369,13 @@
         }
 
         @Override
-        public void freeStorage(long freeStorageSize, PendingIntent pi) {
+        public void freeStorage(long freeStorageSize, IntentSender pi) {
             try {
                 mPM.freeStorage(freeStorageSize, pi);
             } catch (RemoteException e) {
                 // Should never happen!
             }
         }
-
-        @Override
-        public void freeStorageWithIntent(long freeStorageSize, IntentSender pi) {
-            try {
-                mPM.freeStorageWithIntent(freeStorageSize, pi);
-            } catch (RemoteException e) {
-                // Should never happen!
-            }
-        }
         
         @Override
         public void getPackageSizeInfo(String packageName, 
diff --git a/core/java/android/app/FullBackupAgent.java b/core/java/android/app/FullBackupAgent.java
index 89becf4..bc6bb15 100644
--- a/core/java/android/app/FullBackupAgent.java
+++ b/core/java/android/app/FullBackupAgent.java
@@ -48,8 +48,8 @@
         }
 
         // That's the file set; now back it all up
-        FileBackupHelper helper = new FileBackupHelper(this);
-        helper.performBackup(oldState, data, newState, (String[])allFiles.toArray());
+        FileBackupHelper helper = new FileBackupHelper(this, (String[])allFiles.toArray());
+        helper.performBackup(oldState, data, newState);
     }
 
     @Override
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index f6a28b2..e31f4f8 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -446,13 +446,13 @@
             if (ai == null) {
                 throw new RuntimeException("Unable to resolve activity for: " + intent);
             }
-            if (!ai.applicationInfo.processName.equals(
-                    getTargetContext().getPackageName())) {
+            String myProc = mThread.getProcessName();
+            if (!ai.processName.equals(myProc)) {
                 // todo: if this intent is ambiguous, look here to see if
                 // there is a single match that is in our package.
-                throw new RuntimeException("Intent resolved to different package "
-                                           + ai.applicationInfo.packageName + ": "
-                                           + intent);
+                throw new RuntimeException("Intent in process "
+                        + myProc + " resolved to different process "
+                        + ai.processName + ": " + intent);
             }
     
             intent.setComponent(new ComponentName(
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 3a3a983..5d5a277 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -44,6 +44,7 @@
 import android.text.InputType;
 import android.text.TextUtils;
 import android.text.TextWatcher;
+import android.text.util.Regex;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
@@ -55,6 +56,7 @@
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
+import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.AdapterView;
 import android.widget.AutoCompleteTextView;
@@ -145,7 +147,10 @@
     // more than once.
     private final WeakHashMap<String, Drawable> mOutsideDrawablesCache =
             new WeakHashMap<String, Drawable>();
-    
+
+    // Last known IME options value for the search edit text.
+    private int mSearchAutoCompleteImeOptions;
+
     /**
      * Constructor - fires it up and makes it look like the search UI.
      * 
@@ -224,6 +229,8 @@
         
         mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
         mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        mSearchAutoCompleteImeOptions = mSearchAutoComplete.getImeOptions();
     }
 
     /**
@@ -310,15 +317,17 @@
                     + appSearchData + ", " + globalSearch + ")");
         }
         
+        SearchManager searchManager = (SearchManager)
+                mContext.getSystemService(Context.SEARCH_SERVICE);
         // Try to get the searchable info for the provided component (or for global search,
         // if globalSearch == true).
-        mSearchable = SearchManager.getSearchableInfo(componentName, globalSearch);
+        mSearchable = searchManager.getSearchableInfo(componentName, globalSearch);
         
         // If we got back nothing, and it wasn't a request for global search, then try again
         // for global search, as we'll try to launch that in lieu of any component-specific search.
         if (!globalSearch && mSearchable == null) {
             globalSearch = true;
-            mSearchable = SearchManager.getSearchableInfo(componentName, globalSearch);
+            mSearchable = searchManager.getSearchableInfo(componentName, globalSearch);
             
             // If we still get back null (i.e., there's not even a searchable info available
             // for global search), then really give up.
@@ -333,7 +342,7 @@
         mAppSearchData = appSearchData;
         // Using globalSearch here is just an optimization, just calling
         // isDefaultSearchable() should always give the same result.
-        mGlobalSearchMode = globalSearch || SearchManager.isDefaultSearchable(mSearchable); 
+        mGlobalSearchMode = globalSearch || searchManager.isDefaultSearchable(mSearchable);
         mActivityContext = mSearchable.getActivityContext(getContext());
         
         // show the dialog. this will call onStart().
@@ -563,7 +572,8 @@
                 }
             }
             mSearchAutoComplete.setInputType(inputType);
-            mSearchAutoComplete.setImeOptions(mSearchable.getImeOptions());
+            mSearchAutoCompleteImeOptions = mSearchable.getImeOptions();
+            mSearchAutoComplete.setImeOptions(mSearchAutoCompleteImeOptions);
         }
     }
     
@@ -794,7 +804,24 @@
             }
         }
 
-        public void afterTextChanged(Editable s) { }
+        public void afterTextChanged(Editable s) {
+            if (!mSearchAutoComplete.isPerformingCompletion()) {
+                // The user changed the query, check if it is a URL and if so change the search
+                // button in the soft keyboard to the 'Go' button.
+                int options = (mSearchAutoComplete.getImeOptions() & (~EditorInfo.IME_MASK_ACTION));
+                if (Regex.WEB_URL_PATTERN.matcher(mUserQuery).matches()) {
+                    options = options | EditorInfo.IME_ACTION_GO;
+                } else {
+                    options = options | EditorInfo.IME_ACTION_SEARCH;
+                }
+                if (options != mSearchAutoCompleteImeOptions) {
+                    mSearchAutoCompleteImeOptions = options;
+                    mSearchAutoComplete.setImeOptions(options);
+                    // This call is required to update the soft keyboard UI with latest IME flags.
+                    mSearchAutoComplete.setInputType(mSearchAutoComplete.getInputType());
+                }
+            }
+        }
     };
 
     /**
@@ -932,6 +959,32 @@
     }
 
     /**
+     * Corrects http/https typo errors in the given url string, and if the protocol specifier was
+     * not present defaults to http.
+     * 
+     * @param inUrl URL to check and fix
+     * @return fixed URL string.
+     */
+    private String fixUrl(String inUrl) {
+        if (inUrl.startsWith("http://") || inUrl.startsWith("https://"))
+            return inUrl;
+
+        if (inUrl.startsWith("http:") || inUrl.startsWith("https:")) {
+            if (inUrl.startsWith("http:/") || inUrl.startsWith("https:/")) {
+                inUrl = inUrl.replaceFirst("/", "//");
+            } else {
+                inUrl = inUrl.replaceFirst(":", "://");
+            }
+        }
+
+        if (inUrl.indexOf("://") == -1) {
+            inUrl = "http://" + inUrl;
+        }
+
+        return inUrl;
+    }
+
+    /**
      * React to the user typing "enter" or other hardwired keys while typing in the search box.
      * This handles these special keys while the edit box has focus.
      */
@@ -961,7 +1014,19 @@
                 if (keyCode == KeyEvent.KEYCODE_ENTER 
                         && event.getAction() == KeyEvent.ACTION_UP) {
                     v.cancelLongPress();
-                    launchQuerySearch();                    
+
+                    // If this is a url entered by the user and we displayed the 'Go' button which
+                    // the user clicked, launch the url instead of using it as a search query.
+                    if ((mSearchAutoCompleteImeOptions & EditorInfo.IME_MASK_ACTION)
+                            == EditorInfo.IME_ACTION_GO) {
+                        Uri uri = Uri.parse(fixUrl(mSearchAutoComplete.getText().toString()));
+                        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                        launchIntent(intent);
+                    } else {
+                        // Launch as a regular search.
+                        launchQuerySearch();
+                    }
                     return true;
                 }
                 if (event.getAction() == KeyEvent.ACTION_DOWN) {
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index eb80400..fd69ba4 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1514,7 +1514,7 @@
     /**
      * Reference to the shared system search service.
      */
-    private static ISearchManager sService = getSearchManagerService();
+    private static ISearchManager mService;
 
     private final Context mContext;
 
@@ -1529,6 +1529,8 @@
     /*package*/ SearchManager(Context context, Handler handler)  {
         mContext = context;
         mHandler = handler;
+        mService = ISearchManager.Stub.asInterface(
+                ServiceManager.getService(Context.SEARCH_SERVICE));
     }
     
     /**
@@ -1581,7 +1583,7 @@
         try {
             mIsShowing = true;
             // activate the search manager and start it up!
-            sService.startSearch(initialQuery, selectInitialQuery, launchActivity, appSearchData,
+            mService.startSearch(initialQuery, selectInitialQuery, launchActivity, appSearchData,
                     globalSearch, mSearchManagerCallback);
         } catch (RemoteException ex) {
             Log.e(TAG, "startSearch() failed: " + ex);
@@ -1603,7 +1605,7 @@
         if (DBG) debug("stopSearch(), mIsShowing=" + mIsShowing);
         if (!mIsShowing) return;
         try {
-            sService.stopSearch();
+            mService.stopSearch();
             // onDismiss will also clear this, but we do it here too since onDismiss() is
             // called asynchronously.
             mIsShowing = false;
@@ -1725,7 +1727,7 @@
         if (DBG) debug("saveSearchDialog(), mIsShowing=" + mIsShowing);
         if (!mIsShowing) return null;
         try {
-            return sService.onSaveInstanceState();
+            return mService.onSaveInstanceState();
         } catch (RemoteException ex) {
             Log.e(TAG, "onSaveInstanceState() failed: " + ex);
             return null;
@@ -1743,7 +1745,7 @@
         if (DBG) debug("restoreSearchDialog(" + searchDialogState + ")");
         if (searchDialogState == null) return;
         try {
-            sService.onRestoreInstanceState(searchDialogState);
+            mService.onRestoreInstanceState(searchDialogState);
         } catch (RemoteException ex) {
             Log.e(TAG, "onRestoreInstanceState() failed: " + ex);
         }
@@ -1760,17 +1762,12 @@
         if (DBG) debug("onConfigurationChanged(" + newConfig + "), mIsShowing=" + mIsShowing);
         if (!mIsShowing) return;
         try {
-            sService.onConfigurationChanged(newConfig);
+            mService.onConfigurationChanged(newConfig);
         } catch (RemoteException ex) {
             Log.e(TAG, "onConfigurationChanged() failed:" + ex);
         }
     }
 
-    private static ISearchManager getSearchManagerService() {
-        return ISearchManager.Stub.asInterface(
-            ServiceManager.getService(Context.SEARCH_SERVICE));
-    }
-    
     /**
      * Gets information about a searchable activity. This method is static so that it can
      * be used from non-Activity contexts.
@@ -1782,10 +1779,10 @@
      * 
      * @hide because SearchableInfo is not part of the API.
      */
-    public static SearchableInfo getSearchableInfo(ComponentName componentName, 
+    public SearchableInfo getSearchableInfo(ComponentName componentName,
             boolean globalSearch) {
         try {
-            return sService.getSearchableInfo(componentName, globalSearch);
+            return mService.getSearchableInfo(componentName, globalSearch);
         } catch (RemoteException ex) {
             Log.e(TAG, "getSearchableInfo() failed: " + ex);
             return null;
@@ -1797,23 +1794,22 @@
      * 
      * @hide because SearchableInfo is not part of the API.
      */
-    public static boolean isDefaultSearchable(SearchableInfo searchable) {
-        SearchableInfo defaultSearchable = SearchManager.getSearchableInfo(null, true);
+    public boolean isDefaultSearchable(SearchableInfo searchable) {
+        SearchableInfo defaultSearchable = getSearchableInfo(null, true);
         return defaultSearchable != null 
                 && defaultSearchable.getSearchActivity().equals(searchable.getSearchActivity());
     }
-    
+
     /**
-     * Gets a cursor with search suggestions. This method is static so that it can
-     * be used from non-Activity context.
+     * Gets a cursor with search suggestions.
      *
      * @param searchable Information about how to get the suggestions.
      * @param query The search text entered (so far).
-     * @return a cursor with suggestions, or <code>null</null> the suggestion query failed. 
-     * 
+     * @return a cursor with suggestions, or <code>null</null> the suggestion query failed.
+     *
      * @hide because SearchableInfo is not part of the API.
      */
-    public static Cursor getSuggestions(Context context, SearchableInfo searchable, String query) {
+    public Cursor getSuggestions(SearchableInfo searchable, String query) {
         if (searchable == null) {
             return null;
         }
@@ -1852,7 +1848,7 @@
                 .build();
 
         // finally, make the query
-        return context.getContentResolver().query(uri, null, selection, selArgs, null);
+        return mContext.getContentResolver().query(uri, null, selection, selArgs, null);
     }
      
     /**
@@ -1864,9 +1860,9 @@
      * 
      * @hide because SearchableInfo is not part of the API.
      */
-    public static List<SearchableInfo> getSearchablesInGlobalSearch() {
+    public List<SearchableInfo> getSearchablesInGlobalSearch() {
         try {
-            return sService.getSearchablesInGlobalSearch();
+            return mService.getSearchablesInGlobalSearch();
         } catch (RemoteException e) {
             Log.e(TAG, "getSearchablesInGlobalSearch() failed: " + e);
             return null;
@@ -1881,9 +1877,9 @@
      *
      * @hide because SearchableInfo is not part of the API.
      */
-    public static List<SearchableInfo> getSearchablesForWebSearch() {
+    public List<SearchableInfo> getSearchablesForWebSearch() {
         try {
-            return sService.getSearchablesForWebSearch();
+            return mService.getSearchablesForWebSearch();
         } catch (RemoteException e) {
             Log.e(TAG, "getSearchablesForWebSearch() failed: " + e);
             return null;
@@ -1897,9 +1893,9 @@
      *
      * @hide because SearchableInfo is not part of the API.
      */
-    public static SearchableInfo getDefaultSearchableForWebSearch() {
+    public SearchableInfo getDefaultSearchableForWebSearch() {
         try {
-            return sService.getDefaultSearchableForWebSearch();
+            return mService.getDefaultSearchableForWebSearch();
         } catch (RemoteException e) {
             Log.e(TAG, "getDefaultSearchableForWebSearch() failed: " + e);
             return null;
@@ -1913,9 +1909,9 @@
      *
      * @hide
      */
-    public static void setDefaultWebSearch(ComponentName component) {
+    public void setDefaultWebSearch(ComponentName component) {
         try {
-            sService.setDefaultWebSearch(component);
+            mService.setDefaultWebSearch(component);
         } catch (RemoteException e) {
             Log.e(TAG, "setDefaultWebSearch() failed: " + e);
         }
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index ed76f4e..0bdb10b 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -54,6 +54,7 @@
     private static final boolean DBG = false;
     private static final String LOG_TAG = "SuggestionsAdapter";
 
+    private SearchManager mSearchManager;
     private SearchDialog mSearchDialog;
     private SearchableInfo mSearchable;
     private Context mProviderContext;
@@ -92,6 +93,7 @@
                 com.android.internal.R.layout.search_dropdown_item_icons_2line,
                 null,   // no initial cursor
                 true);  // auto-requery
+        mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
         mSearchDialog = searchDialog;
         mSearchable = searchable;
 
@@ -142,7 +144,7 @@
             mSearchDialog.getWindow().getDecorView().post(mStartSpinnerRunnable);
         }
         try {
-            final Cursor cursor = SearchManager.getSuggestions(mContext, mSearchable, query);
+            final Cursor cursor = mSearchManager.getSuggestions(mSearchable, query);
             // trigger fill window so the spinner stays up until the results are copied over and
             // closer to being ready
             if (!mGlobalSearchMode) cursor.getCount();
diff --git a/core/java/android/backup/BackupDataOutput.java b/core/java/android/backup/BackupDataOutput.java
index a6d5bec..d29c5ba 100644
--- a/core/java/android/backup/BackupDataOutput.java
+++ b/core/java/android/backup/BackupDataOutput.java
@@ -36,6 +36,7 @@
         }
     }
 
+    // A dataSize of -1 indicates that the record under this key should be deleted
     public int writeEntityHeader(String key, int dataSize) throws IOException {
         int result = writeEntityHeader_native(mBackupWriter, key, dataSize);
         if (result >= 0) {
@@ -54,6 +55,10 @@
         }
     }
 
+    public void setKeyPrefix(String keyPrefix) {
+        setKeyPrefix_native(mBackupWriter, keyPrefix);
+    }
+
     protected void finalize() throws Throwable {
         try {
             dtor(mBackupWriter);
@@ -61,11 +66,12 @@
             super.finalize();
         }
     }
-        
+
     private native static int ctor(FileDescriptor fd);
     private native static void dtor(int mBackupWriter);
 
     private native static int writeEntityHeader_native(int mBackupWriter, String key, int dataSize);
     private native static int writeEntityData_native(int mBackupWriter, byte[] data, int size);
+    private native static void setKeyPrefix_native(int mBackupWriter, String keyPrefix);
 }
 
diff --git a/core/java/android/backup/RestoreHelper.java b/core/java/android/backup/BackupHelper.java
similarity index 61%
rename from core/java/android/backup/RestoreHelper.java
rename to core/java/android/backup/BackupHelper.java
index ac7d8ee..3983e28 100644
--- a/core/java/android/backup/RestoreHelper.java
+++ b/core/java/android/backup/BackupHelper.java
@@ -16,16 +16,31 @@
 
 package android.backup;
 
+import android.os.ParcelFileDescriptor;
+
 import java.io.InputStream;
 
 /** @hide */
-public interface RestoreHelper {
+public interface BackupHelper {
     /**
-     * Called by RestoreHelperDispatcher to dispatch one entity of data.
+     * Based on oldState, determine which of the files from the application's data directory
+     * need to be backed up, write them to the data stream, and fill in newState with the
+     * state as it exists now.
+     */
+    public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState);
+
+    /**
+     * Called by BackupHelperDispatcher to dispatch one entity of data.
      * <p class=note>
      * Do not close the <code>data</code> stream.  Do not read more than
      * <code>dataSize</code> bytes from <code>data</code>.
      */
     public void restoreEntity(BackupDataInputStream data);
+
+    /**
+     *
+     */
+    public void writeRestoreSnapshot(ParcelFileDescriptor fd);
 }
 
diff --git a/core/java/android/backup/BackupHelperAgent.java b/core/java/android/backup/BackupHelperAgent.java
new file mode 100644
index 0000000..f7eb1b8
--- /dev/null
+++ b/core/java/android/backup/BackupHelperAgent.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 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.backup;
+
+import android.app.BackupAgent;
+import android.backup.BackupHelper;
+import android.backup.BackupHelperDispatcher;
+import android.backup.BackupDataInput;
+import android.backup.BackupDataOutput;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.IOException;
+
+/** @hide */
+public class BackupHelperAgent extends BackupAgent {
+    static final String TAG = "BackupHelperAgent";
+
+    BackupHelperDispatcher mDispatcher = new BackupHelperDispatcher();
+
+    @Override
+    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+             ParcelFileDescriptor newState) {
+        mDispatcher.performBackup(oldState, data, newState);
+    }
+
+    @Override
+    public void onRestore(BackupDataInput data, ParcelFileDescriptor newState)
+            throws IOException {
+        mDispatcher.performRestore(data, newState);
+    }
+
+    public BackupHelperDispatcher getDispatcher() {
+        return mDispatcher;
+    }
+
+    public void addHelper(String keyPrefix, BackupHelper helper) {
+        mDispatcher.addHelper(keyPrefix, helper);
+    }
+}
+
+
diff --git a/core/java/android/backup/BackupHelperDispatcher.java b/core/java/android/backup/BackupHelperDispatcher.java
new file mode 100644
index 0000000..e9a8f71
--- /dev/null
+++ b/core/java/android/backup/BackupHelperDispatcher.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2009 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.backup;
+
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.TreeMap;
+import java.util.Map;
+
+/** @hide */
+public class BackupHelperDispatcher {
+    private static final String TAG = "BackupHelperDispatcher";
+
+    TreeMap<String,BackupHelper> mHelpers = new TreeMap<String,BackupHelper>();
+    
+    public BackupHelperDispatcher() {
+    }
+
+    public void addHelper(String keyPrefix, BackupHelper helper) {
+        mHelpers.put(keyPrefix, helper);
+    }
+
+    /** TODO: Make this save and restore the key prefix. */
+    public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+             ParcelFileDescriptor newState) {
+        // Write out the state files -- mHelpers is a TreeMap, so the order is well defined.
+        for (Map.Entry<String,BackupHelper> entry: mHelpers.entrySet()) {
+            data.setKeyPrefix(entry.getKey());
+            entry.getValue().performBackup(oldState, data, newState);
+        }
+    }
+
+    public void performRestore(BackupDataInput input, ParcelFileDescriptor newState)
+            throws IOException {
+        boolean alreadyComplained = false;
+
+        BackupDataInputStream stream = new BackupDataInputStream(input);
+        while (input.readNextHeader()) {
+
+            String rawKey = input.getKey();
+            int pos = rawKey.indexOf(':');
+            if (pos > 0) {
+                String prefix = rawKey.substring(0, pos);
+                BackupHelper helper = mHelpers.get(prefix);
+                if (helper != null) {
+                    stream.dataSize = input.getDataSize();
+                    stream.key = rawKey.substring(pos+1);
+                    helper.restoreEntity(stream);
+                } else {
+                    if (!alreadyComplained) {
+                        Log.w(TAG, "Couldn't find helper for: '" + rawKey + "'");
+                        alreadyComplained = true;
+                    }
+                }
+            } else {
+                if (!alreadyComplained) {
+                    Log.w(TAG, "Entity with no prefix: '" + rawKey + "'");
+                    alreadyComplained = true;
+                }
+            }
+            input.skipEntityData(); // In case they didn't consume the data.
+        }
+
+        // Write out the state files -- mHelpers is a TreeMap, so the order is well defined.
+        for (BackupHelper helper: mHelpers.values()) {
+            helper.writeRestoreSnapshot(newState);
+        }
+    }
+}
+
diff --git a/core/java/android/backup/FileBackupHelper.java b/core/java/android/backup/FileBackupHelper.java
index ed840bb..4058497 100644
--- a/core/java/android/backup/FileBackupHelper.java
+++ b/core/java/android/backup/FileBackupHelper.java
@@ -24,19 +24,19 @@
 import java.io.FileDescriptor;
 
 /** @hide */
-public class FileBackupHelper {
+public class FileBackupHelper extends FileBackupHelperBase implements BackupHelper {
     private static final String TAG = "FileBackupHelper";
 
     Context mContext;
-    String mKeyPrefix;
+    File mFilesDir;
+    String[] mFiles;
 
-    public FileBackupHelper(Context context) {
-        mContext = context;
-    }
+    public FileBackupHelper(Context context, String... files) {
+        super(context);
 
-    public FileBackupHelper(Context context, String keyPrefix) {
         mContext = context;
-        mKeyPrefix = keyPrefix;
+        mFilesDir = context.getFilesDir();
+        mFiles = files;
     }
 
     /**
@@ -45,8 +45,9 @@
      * state as it exists now.
      */
     public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
-            ParcelFileDescriptor newState, String[] files) {
+            ParcelFileDescriptor newState) {
         // file names
+        String[] files = mFiles;
         File base = mContext.getFilesDir();
         final int N = files.length;
         String[] fullPaths = new String[N];
@@ -54,66 +55,18 @@
             fullPaths[i] = (new File(base, files[i])).getAbsolutePath();
         }
 
-        // keys
-        String[] keys = makeKeys(mKeyPrefix, files);
-
         // go
-        performBackup_checked(oldState, data, newState, fullPaths, keys);
+        performBackup_checked(oldState, data, newState, fullPaths, files);
     }
 
-    /**
-     * If keyPrefix is not null, prepend it to each of the strings in <code>original</code>;
-     * otherwise, return original.
-     */
-    static String[] makeKeys(String keyPrefix, String[] original) {
-        if (keyPrefix != null) {
-            String[] keys;
-            final int N = original.length;
-            keys = new String[N];
-            for (int i=0; i<N; i++) {
-                keys[i] = keyPrefix + ':' + original[i];
-            }
-            return keys;
-        } else {
-            return original;
+    public void restoreEntity(BackupDataInputStream data) {
+        // TODO: turn this off before ship
+        Log.d(TAG, "got entity '" + data.getKey() + "' size=" + data.size());
+        String key = data.getKey();
+        if (isKeyInList(key, mFiles)) {
+            File f = new File(mFilesDir, key);
+            writeFile(f, data);
         }
     }
-
-    /**
-     * Check the parameters so the native code doens't have to throw all the exceptions
-     * since it's easier to do that from java.
-     */
-    static void performBackup_checked(ParcelFileDescriptor oldState, BackupDataOutput data,
-            ParcelFileDescriptor newState, String[] files, String[] keys) {
-        if (files.length == 0) {
-            return;
-        }
-        // files must be all absolute paths
-        for (String f: files) {
-            if (f.charAt(0) != '/') {
-                throw new RuntimeException("files must have all absolute paths: " + f);
-            }
-        }
-        // the length of files and keys must be the same
-        if (files.length != keys.length) {
-            throw new RuntimeException("files.length=" + files.length
-                    + " keys.length=" + keys.length);
-        }
-        // oldStateFd can be null
-        FileDescriptor oldStateFd = oldState != null ? oldState.getFileDescriptor() : null;
-        FileDescriptor newStateFd = newState.getFileDescriptor();
-        if (newStateFd == null) {
-            throw new NullPointerException();
-        }
-
-        int err = performBackup_native(oldStateFd, data.mBackupWriter, newStateFd, files, keys);
-
-        if (err != 0) {
-            // TODO: more here
-            throw new RuntimeException("Backup failed 0x" + Integer.toHexString(err));
-        }
-    }
-
-    native private static int performBackup_native(FileDescriptor oldState,
-            int data, FileDescriptor newState, String[] files, String[] keys);
 }
+
diff --git a/core/java/android/backup/FileBackupHelperBase.java b/core/java/android/backup/FileBackupHelperBase.java
new file mode 100644
index 0000000..03ae476
--- /dev/null
+++ b/core/java/android/backup/FileBackupHelperBase.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2009 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.backup;
+
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.InputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+
+class FileBackupHelperBase {
+    private static final String TAG = "RestoreHelperBase";
+
+    int mPtr;
+    Context mContext;
+    boolean mExceptionLogged;
+    
+    FileBackupHelperBase(Context context) {
+        mPtr = ctor();
+        mContext = context;
+    }
+
+    protected void finalize() throws Throwable {
+        try {
+            dtor(mPtr);
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Check the parameters so the native code doens't have to throw all the exceptions
+     * since it's easier to do that from java.
+     */
+    static void performBackup_checked(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState, String[] files, String[] keys) {
+        if (files.length == 0) {
+            return;
+        }
+        // files must be all absolute paths
+        for (String f: files) {
+            if (f.charAt(0) != '/') {
+                throw new RuntimeException("files must have all absolute paths: " + f);
+            }
+        }
+        // the length of files and keys must be the same
+        if (files.length != keys.length) {
+            throw new RuntimeException("files.length=" + files.length
+                    + " keys.length=" + keys.length);
+        }
+        // oldStateFd can be null
+        FileDescriptor oldStateFd = oldState != null ? oldState.getFileDescriptor() : null;
+        FileDescriptor newStateFd = newState.getFileDescriptor();
+        if (newStateFd == null) {
+            throw new NullPointerException();
+        }
+
+        int err = performBackup_native(oldStateFd, data.mBackupWriter, newStateFd, files, keys);
+
+        if (err != 0) {
+            // TODO: more here
+            throw new RuntimeException("Backup failed 0x" + Integer.toHexString(err));
+        }
+    }
+
+    void writeFile(File f, InputStream in) {
+        if (!(in instanceof BackupDataInputStream)) {
+            throw new IllegalStateException("input stream must be a BackupDataInputStream");
+        }
+        int result = -1;
+
+        // Create the enclosing directory.
+        File parent = f.getParentFile();
+        parent.mkdirs();
+
+        result = writeFile_native(mPtr, f.getAbsolutePath(),
+                ((BackupDataInputStream)in).mData.mBackupReader);
+        if (result != 0) {
+            // Bail on this entity.  Only log one failure per helper object.
+            if (!mExceptionLogged) {
+                Log.e(TAG, "Failed restoring file '" + f + "' for app '"
+                        + mContext.getPackageName() + "\' result=0x"
+                        + Integer.toHexString(result));
+                mExceptionLogged = true;
+            }
+        }
+    }
+
+    public void writeRestoreSnapshot(ParcelFileDescriptor fd) {
+        int result = writeSnapshot_native(mPtr, fd.getFileDescriptor());
+        // TODO: Do something with the error.
+    }
+
+    boolean isKeyInList(String key, String[] list) {
+        for (String s: list) {
+            if (s.equals(key)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static native int ctor();
+    private static native void dtor(int ptr);
+
+    native private static int performBackup_native(FileDescriptor oldState,
+            int data, FileDescriptor newState, String[] files, String[] keys);
+    
+    private static native int writeFile_native(int ptr, String filename, int backupReader);
+    private static native int writeSnapshot_native(int ptr, FileDescriptor fd);
+}
+
+
diff --git a/core/java/android/backup/FileRestoreHelper.java b/core/java/android/backup/FileRestoreHelper.java
deleted file mode 100644
index b7e3625..0000000
--- a/core/java/android/backup/FileRestoreHelper.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2009 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.backup;
-
-import android.content.Context;
-import android.util.Log;
-
-import java.io.File;
-
-/** @hide */
-public class FileRestoreHelper extends RestoreHelperBase implements RestoreHelper {
-    private static final String TAG = "FileRestoreHelper";
-
-    File mFilesDir;
-
-    public FileRestoreHelper(Context context) {
-        super(context);
-        mFilesDir = context.getFilesDir();
-    }
-
-    public void restoreEntity(BackupDataInputStream data) {
-        Log.d(TAG, "got entity '" + data.getKey() + "' size=" + data.size()); // TODO: turn this off before ship
-        File f = new File(mFilesDir, data.getKey());
-        writeFile(f, data);
-    }
-}
-
diff --git a/core/java/android/backup/RestoreHelperBase.java b/core/java/android/backup/RestoreHelperBase.java
deleted file mode 100644
index 894c9af..0000000
--- a/core/java/android/backup/RestoreHelperBase.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2009 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.backup;
-
-import android.content.Context;
-import android.util.Log;
-
-import java.io.InputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-class RestoreHelperBase {
-    private static final String TAG = "RestoreHelperBase";
-    private static final int BUF_SIZE = 8 * 1024;
-
-    Context mContext;
-    byte[] mBuf = new byte[BUF_SIZE];
-    boolean mExceptionLogged;
-    
-    RestoreHelperBase(Context context) {
-        mContext = context;
-    }
-
-    void writeFile(File f, InputStream in) {
-        boolean success = false;
-        FileOutputStream out = null;
-        try {
-            // Create the enclosing directory.
-            File parent = f.getParentFile();
-            parent.mkdirs();
-
-            // Copy the file.
-            int sum = 0;
-            out = new FileOutputStream(f);
-            byte[] buf = mBuf;
-            int amt;
-            while ((amt = in.read(buf)) > 0) {
-                out.write(buf, 0, amt);
-                sum += amt;
-            }
-
-            // TODO: Set the permissions of the file.
-
-            // We're done
-            success = true;
-            out = null;
-        } catch (IOException ex) {
-            // Bail on this entity.  Only log one exception per helper object.
-            if (!mExceptionLogged) {
-                Log.e(TAG, "Failed restoring file '" + f + "' for app '"
-                    + mContext.getPackageName() + '\'', ex);
-                mExceptionLogged = true;
-            }
-        }
-        finally {
-            if (out != null) {
-                try {
-                    out.close();
-                } catch (IOException ex) {
-                }
-            }
-            if (!success) {
-                // Something didn't work out, delete the file
-                f.delete();
-            }
-        }
-    }
-}
-
-
diff --git a/core/java/android/backup/RestoreHelperDispatcher.java b/core/java/android/backup/RestoreHelperDispatcher.java
deleted file mode 100644
index 5928914..0000000
--- a/core/java/android/backup/RestoreHelperDispatcher.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2009 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.backup;
-
-import android.util.Log;
-
-import java.io.IOException;
-import java.util.HashMap;
-
-/** @hide */
-public class RestoreHelperDispatcher {
-    private static final String TAG = "RestoreHelperDispatcher";
-
-    HashMap<String,RestoreHelper> mHelpers = new HashMap<String,RestoreHelper>();
-
-    public void addHelper(String keyPrefix, RestoreHelper helper) {
-        mHelpers.put(keyPrefix, helper);
-    }
-
-    public void dispatch(BackupDataInput input) throws IOException {
-        boolean alreadyComplained = false;
-
-        BackupDataInputStream stream = new BackupDataInputStream(input);
-        while (input.readNextHeader()) {
-
-            String rawKey = input.getKey();
-            int pos = rawKey.indexOf(':');
-            if (pos > 0) {
-                String prefix = rawKey.substring(0, pos);
-                RestoreHelper helper = mHelpers.get(prefix);
-                if (helper != null) {
-                    stream.dataSize = input.getDataSize();
-                    stream.key = rawKey.substring(pos+1);
-                    helper.restoreEntity(stream);
-                } else {
-                    if (!alreadyComplained) {
-                        Log.w(TAG, "Couldn't find helper for: '" + rawKey + "'");
-                        alreadyComplained = true;
-                    }
-                }
-            } else {
-                if (!alreadyComplained) {
-                    Log.w(TAG, "Entity with no prefix: '" + rawKey + "'");
-                    alreadyComplained = true;
-                }
-            }
-            input.skipEntityData(); // In case they didn't consume the data.
-        }
-    }
-}
diff --git a/core/java/android/backup/SharedPreferencesBackupHelper.java b/core/java/android/backup/SharedPreferencesBackupHelper.java
index cad79df..f492629 100644
--- a/core/java/android/backup/SharedPreferencesBackupHelper.java
+++ b/core/java/android/backup/SharedPreferencesBackupHelper.java
@@ -18,39 +18,51 @@
 
 import android.content.Context;
 import android.os.ParcelFileDescriptor;
+import android.util.Log;
 
+import java.io.File;
 import java.io.FileDescriptor;
 
 /** @hide */
-public class SharedPreferencesBackupHelper {
+public class SharedPreferencesBackupHelper extends FileBackupHelperBase implements BackupHelper {
+    private static final String TAG = "SharedPreferencesBackupHelper";
+
     private Context mContext;
-    private String mKeyPrefix;
+    private String[] mPrefGroups;
 
-    public SharedPreferencesBackupHelper(Context context) {
+    public SharedPreferencesBackupHelper(Context context, String[] prefGroups) {
+        super(context);
+
         mContext = context;
+        mPrefGroups = prefGroups;
     }
 
-    public SharedPreferencesBackupHelper(Context context, String keyPrefix) {
-        mContext = context;
-        mKeyPrefix = keyPrefix;
-    }
-    
-    public void performBackup(ParcelFileDescriptor oldSnapshot, ParcelFileDescriptor newSnapshot,
-            BackupDataOutput data, String[] prefGroups) {
+    public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState) {
         Context context = mContext;
         
         // make filenames for the prefGroups
+        String[] prefGroups = mPrefGroups;
         final int N = prefGroups.length;
         String[] files = new String[N];
         for (int i=0; i<N; i++) {
             files[i] = context.getSharedPrefsFile(prefGroups[i]).getAbsolutePath();
         }
 
-        // make keys if necessary
-        String[] keys = FileBackupHelper.makeKeys(mKeyPrefix, prefGroups);
-
         // go
-        FileBackupHelper.performBackup_checked(oldSnapshot, data, newSnapshot, files, prefGroups);
+        performBackup_checked(oldState, data, newState, files, prefGroups);
+    }
+
+    public void restoreEntity(BackupDataInputStream data) {
+        Context context = mContext;
+        
+        // TODO: turn this off before ship
+        Log.d(TAG, "got entity '" + data.getKey() + "' size=" + data.size());
+        String key = data.getKey();
+        if (isKeyInList(key, mPrefGroups)) {
+            File f = context.getSharedPrefsFile(key).getAbsoluteFile();
+            writeFile(f, data);
+        }
     }
 }
 
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index e198435..fe1e09a 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -332,6 +332,31 @@
     }
 
     /**
+     * Get battery usage hint for Bluetooth Headset service.
+     * This is a monotonically increasing integer. Wraps to 0 at
+     * Integer.MAX_INT, and at boot.
+     * Current implementation returns the number of AT commands handled since
+     * boot. This is a good indicator for spammy headset/handsfree units that
+     * can keep the device awake by polling for cellular status updates. As a
+     * rule of thumb, each AT command prevents the CPU from sleeping for 500 ms
+     * @return monotonically increasing battery usage hint, or a negative error
+     *         code on error
+     * @hide
+     */
+    public int getBatteryUsageHint() {
+        if (DBG) log("getBatteryUsageHint()");
+        if (mService != null) {
+            try {
+                return mService.getBatteryUsageHint();
+            } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+        }
+        return -1;
+    }
+
+    /**
      * Check class bits for possible HSP or HFP support.
      * This is a simple heuristic that tries to guess if a device with the
      * given class bits might support HSP or HFP. It is not accurate for all
diff --git a/core/java/android/bluetooth/BluetoothInputStream.java b/core/java/android/bluetooth/BluetoothInputStream.java
index e6f501c..c060f32 100644
--- a/core/java/android/bluetooth/BluetoothInputStream.java
+++ b/core/java/android/bluetooth/BluetoothInputStream.java
@@ -59,7 +59,7 @@
         byte b[] = new byte[1];
         int ret = mSocket.readNative(b, 0, 1);
         if (ret == 1) {
-            return (int)b[0];
+            return (int)b[0] & 0xff;
         } else {
             return -1;
         }
diff --git a/core/java/android/bluetooth/HeadsetBase.java b/core/java/android/bluetooth/HeadsetBase.java
index f31e7a2..f987ffd 100644
--- a/core/java/android/bluetooth/HeadsetBase.java
+++ b/core/java/android/bluetooth/HeadsetBase.java
@@ -40,6 +40,8 @@
     public static final int DIRECTION_INCOMING = 1;
     public static final int DIRECTION_OUTGOING = 2;
 
+    private static int sAtInputCount = 0;  /* TODO: Consider not using a static variable */
+
     private final BluetoothDevice mBluetooth;
     private final String mAddress;
     private final int mRfcommChannel;
@@ -109,6 +111,14 @@
         acquireWakeLock();
         long timestamp;
 
+        synchronized(HeadsetBase.class) {
+            if (sAtInputCount == Integer.MAX_VALUE) {
+                sAtInputCount = 0;
+            } else {
+                sAtInputCount++;
+            }
+        }
+
         if (DBG) timestamp = System.currentTimeMillis();
         AtCommandResult result = mAtParser.process(input);
         if (DBG) Log.d(TAG, "Processing " + input + " took " +
@@ -279,7 +289,11 @@
         }
     }
 
-    private void log(String msg) {
+    public static int getAtInputCount() {
+        return sAtInputCount;
+    }
+
+    private static void log(String msg) {
         Log.d(TAG, msg);
     }
 }
diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl
index 582d4e3..5f42fd6 100644
--- a/core/java/android/bluetooth/IBluetoothHeadset.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl
@@ -31,4 +31,5 @@
     boolean stopVoiceRecognition();
     boolean setPriority(in String address, int priority);
     int getPriority(in String address);
+    int getBatteryUsageHint();
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 4ccbf18..6c8bafc 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
@@ -233,6 +234,9 @@
     /** Return the name of this application's package. */
     public abstract String getPackageName();
 
+    /** Return the full application info for this context's package. */
+    public abstract ApplicationInfo getApplicationInfo();
+    
     /**
      * {@hide}
      * Return the full path to this context's resource files.  This is the ZIP files
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 262204e..7513b3b 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
@@ -120,6 +121,11 @@
     }
 
     @Override
+    public ApplicationInfo getApplicationInfo() {
+        return mBase.getApplicationInfo();
+    }
+    
+    @Override
     public String getPackageResourcePath() {
         return mBase.getPackageResourcePath();
     }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 65d09c9..33e769e 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -915,6 +915,23 @@
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_SEND = "android.intent.action.SEND";
     /**
+     * Activity Action: Deliver multiple data to someone else.
+     * <p>
+     * Like ACTION_SEND, except the data is multiple.
+     * <p>
+     * Input: {@link #getType} is the MIME type of the data being sent.
+     * get*ArrayListExtra can have either a {@link #EXTRA_TEXT} or {@link
+     * #EXTRA_STREAM} field, containing the data to be sent.
+     * <p>
+     * Optional standard extras, which may be interpreted by some recipients as
+     * appropriate, are: {@link #EXTRA_EMAIL}, {@link #EXTRA_CC},
+     * {@link #EXTRA_BCC}, {@link #EXTRA_SUBJECT}.
+     * <p>
+     * Output: nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
+    /**
      * Activity Action: Handle an incoming phone call.
      * <p>Input: nothing.
      * <p>Output: nothing.
@@ -1059,6 +1076,15 @@
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
+
+    /**
+     * Activity Action: Show power usage information to the user.
+     * <p>Input: Nothing.
+     * <p>Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
+    
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard intent broadcast actions (see action variable).
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index f10dd53..2a2cf93 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -137,6 +137,13 @@
     public static final int FLAG_TEST_ONLY = 1<<8;
 
     /**
+     * Value for {@link #flags}: true when the application's window can be
+     * expanded over default window size in target density (320x480 for
+     * 1.0 density, 480x720 for 1.5 density etc)
+     */
+    public static final int FLAG_SUPPORTS_LARGE_SCREENS = 1<<9;
+    
+    /**
      * Value for {@link #flags}: this is false if the application has set
      * its android:allowBackup to false, true otherwise.
      * 
@@ -201,12 +208,6 @@
     public int[] supportsDensities;
 
     /**
-     * True when the application's window can be expanded over default window
-     * size in target density (320x480 for 1.0 density, 480x720 for 1.5 density etc)
-     */
-    public boolean expandable = false;
-
-    /**
      * The minimum SDK version this application targets.  It may run on earilier
      * versions, but it knows how to work with any new behavior added at this
      * version.  Will be {@link android.os.Build.VERSION_CODES#CUR_DEVELOPMENT}
@@ -240,7 +241,6 @@
         pw.println(prefix + "manageSpaceActivityName="+manageSpaceActivityName);
         pw.println(prefix + "description=0x"+Integer.toHexString(descriptionRes));
         pw.println(prefix + "supportsDensities=" + supportsDensities);
-        pw.println(prefix + "expandable=" + expandable);
         super.dumpBack(pw, prefix);
     }
     
@@ -288,7 +288,6 @@
         manageSpaceActivityName = orig.manageSpaceActivityName;
         descriptionRes = orig.descriptionRes;
         supportsDensities = orig.supportsDensities;
-        expandable = orig.expandable;
     }
 
 
@@ -321,7 +320,6 @@
         dest.writeString(backupAgentName);
         dest.writeInt(descriptionRes);
         dest.writeIntArray(supportsDensities);
-        dest.writeInt(expandable ? 1 : 0);
     }
 
     public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -353,7 +351,6 @@
         backupAgentName = source.readString();
         descriptionRes = source.readInt();
         supportsDensities = source.createIntArray();
-        expandable = source.readInt() != 0;
     }
 
     /**
@@ -383,7 +380,7 @@
      * @hide
      */
     public void disableCompatibilityMode() {
-        expandable = true;
+        flags |= FLAG_SUPPORTS_LARGE_SCREENS;
         supportsDensities = ANY_DENSITIES_ARRAY;
     }
 }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index e90dae6..68f8417 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -34,7 +34,6 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.net.Uri;
-import android.app.PendingIntent;
 import android.content.IntentSender;
 
 /**
@@ -236,35 +235,11 @@
      * and the current free storage is YY,
      * if XX is less than YY, just return. if not free XX-YY number
      * of bytes if possible.
-     * @param opFinishedIntent PendingIntent call back used to
-     * notify when the operation is completed.May be null
-     * to indicate that no call back is desired.
-     */
-     void freeStorage(in long freeStorageSize,
-             in PendingIntent opFinishedIntent);
-
-    /**
-     * Free storage by deleting LRU sorted list of cache files across
-     * all applications. If the currently available free storage
-     * on the device is greater than or equal to the requested
-     * free storage, no cache files are cleared. If the currently
-     * available storage on the device is less than the requested
-     * free storage, some or all of the cache files across
-     * all applications are deleted (based on last accessed time)
-     * to increase the free storage space on the device to
-     * the requested value. There is no guarantee that clearing all
-     * the cache files from all applications will clear up
-     * enough storage to achieve the desired value.
-     * @param freeStorageSize The number of bytes of storage to be
-     * freed by the system. Say if freeStorageSize is XX,
-     * and the current free storage is YY,
-     * if XX is less than YY, just return. if not free XX-YY number
-     * of bytes if possible.
      * @param pi IntentSender call back used to
      * notify when the operation is completed.May be null
      * to indicate that no call back is desired.
      */
-     void freeStorageWithIntent(in long freeStorageSize,
+     void freeStorage(in long freeStorageSize,
              in IntentSender pi);
      
     /**
@@ -302,4 +277,11 @@
     boolean isSafeMode();
     void systemReady();
     boolean hasSystemUidErrors();
+    
+    /**
+     * Ask the package manager to perform dex-opt (if needed) on the given
+     * package, if it already hasn't done mode.  Only does this if running
+     * in the special development "no pre-dexopt" mode.
+     */
+    boolean performDexOpt(String packageName);
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 116b3d4..3250a87 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -16,8 +16,6 @@
 
 package android.content.pm;
 
-
-import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -181,12 +179,6 @@
     public static final int MATCH_DEFAULT_ONLY   = 0x00010000;
 
     /**
-     * {@link ApplicationInfo} flag: return the
-     * {link ApplicationInfo#expandable} boolean flag of the package.
-     */
-    public static final int GET_EXPANDABLE = 0x00020000;
-
-    /**
      * Permission check result: this is returned by {@link #checkPermission}
      * if the permission has been granted to the given package.
      */
@@ -1522,40 +1514,13 @@
      * and the current free storage is YY,
      * if XX is less than YY, just return. if not free XX-YY number
      * of bytes if possible.
-     * @param opFinishedIntent PendingIntent call back used to
-     * notify when the operation is completed.May be null
-     * to indicate that no call back is desired.
-     *
-     * @deprecated
-     * @hide
-     */
-    @Deprecated
-    public abstract void freeStorage(long freeStorageSize, PendingIntent opFinishedIntent);
-
-    /**
-     * Free storage by deleting LRU sorted list of cache files across
-     * all applications. If the currently available free storage
-     * on the device is greater than or equal to the requested
-     * free storage, no cache files are cleared. If the currently
-     * available storage on the device is less than the requested
-     * free storage, some or all of the cache files across
-     * all applications are deleted (based on last accessed time)
-     * to increase the free storage space on the device to
-     * the requested value. There is no guarantee that clearing all
-     * the cache files from all applications will clear up
-     * enough storage to achieve the desired value.
-     * @param freeStorageSize The number of bytes of storage to be
-     * freed by the system. Say if freeStorageSize is XX,
-     * and the current free storage is YY,
-     * if XX is less than YY, just return. if not free XX-YY number
-     * of bytes if possible.
      * @param pi IntentSender call back used to
      * notify when the operation is completed.May be null
      * to indicate that no call back is desired.
      * 
      * @hide
      */
-    public abstract void freeStorageWithIntent(long freeStorageSize, IntentSender pi);
+    public abstract void freeStorage(long freeStorageSize, IntentSender pi);
 
     /**
      * Retrieve the size information for a package.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ab8559c..ab9518e 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -777,7 +777,7 @@
                             targetCode = minCode = val.string.toString();
                         } else {
                             // If it's not a string, it's an integer.
-                            minVers = val.data;
+                            targetVers = minVers = val.data;
                         }
                     }
                     
@@ -798,6 +798,25 @@
 
                     sa.recycle();
 
+                    if (minCode != null) {
+                        if (!minCode.equals(mSdkCodename)) {
+                            if (mSdkCodename != null) {
+                                outError[0] = "Requires development platform " + minCode
+                                        + " (current platform is " + mSdkCodename + ")";
+                            } else {
+                                outError[0] = "Requires development platform " + minCode
+                                        + " but this is a release platform.";
+                            }
+                            mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
+                            return null;
+                        }
+                    } else if (minVers > mSdkVersion) {
+                        outError[0] = "Requires newer sdk version #" + minVers
+                                + " (current version is #" + mSdkVersion + ")";
+                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
+                        return null;
+                    }
+                    
                     if (targetCode != null) {
                         if (!targetCode.equals(mSdkCodename)) {
                             if (mSdkCodename != null) {
@@ -817,13 +836,6 @@
                         pkg.applicationInfo.targetSdkVersion = targetVers;
                     }
                     
-                    if (minVers > mSdkVersion) {
-                        outError[0] = "Requires newer sdk version #" + minVers
-                                + " (current version is #" + mSdkVersion + ")";
-                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
-                        return null;
-                    }
-                    
                     if (maxVers < mSdkVersion) {
                         outError[0] = "Requires older sdk version #" + maxVers
                                 + " (current version is #" + mSdkVersion + ")";
@@ -865,7 +877,7 @@
                 XmlUtils.skipCurrentTag(parser);
 
             } else if (tagName.equals("expandable")) {
-                pkg.expandable = true;
+                pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
                 XmlUtils.skipCurrentTag(parser);
             } else {
                 Log.w(TAG, "Bad element under <manifest>: "
@@ -2262,9 +2274,6 @@
         public final ArrayList<Integer> supportsDensityList = new ArrayList<Integer>();
         public int[] supportsDensities = null;
 
-        // If the application's window is expandable.
-        public boolean expandable;
-        
         // If this is a 3rd party app, this is the path of the zip file.
         public String mPath;
 
@@ -2287,6 +2296,17 @@
         // preferred up order.
         public int mPreferredOrder = 0;
 
+        // For use by package manager service to keep track of which apps
+        // have been installed with forward locking.
+        public boolean mForwardLocked;
+        
+        // For use by the package manager to keep track of the path to the
+        // file an app came from.
+        public String mScanPath;
+        
+        // For use by package manager to keep track of where it has done dexopt.
+        public boolean mDidDexOpt;
+        
         // Additional data supplied by callers.
         public Object mExtras;
         
@@ -2439,9 +2459,6 @@
                 && p.supportsDensities != null) {
             return true;
         }
-        if ((flags & PackageManager.GET_EXPANDABLE) != 0) {
-            return true;
-        }
         return false;
     }
 
@@ -2462,9 +2479,6 @@
         if ((flags & PackageManager.GET_SUPPORTS_DENSITIES) != 0) {
             ai.supportsDensities = p.supportsDensities;
         }
-        if ((flags & PackageManager.GET_EXPANDABLE) != 0) {
-            ai.expandable = p.expandable;
-        }
         return ai;
     }
 
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 836de39..680fef8 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -69,7 +69,8 @@
     public final boolean mScalingRequired;
 
     public CompatibilityInfo(ApplicationInfo appInfo) {
-        mExpandable = mConfiguredExpandable = appInfo.expandable;
+        mExpandable = mConfiguredExpandable =
+            (appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0;
         
         float packageDensityScale = -1.0f;
         if (appInfo.supportsDensities != null) {
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 2f63820..71dbd38 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -22,11 +22,9 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.app.ActivityThread.PackageInfo;
 import android.content.pm.ApplicationInfo;
 import android.graphics.Movie;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.os.Bundle;
 import android.os.SystemProperties;
@@ -35,6 +33,7 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.TypedValue;
+import android.util.LongSparseArray;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -59,19 +58,19 @@
     // Information about preloaded resources.  Note that they are not
     // protected by a lock, because while preloading in zygote we are all
     // single-threaded, and after that these are immutable.
-    private static final SparseArray<Drawable.ConstantState> sPreloadedDrawables
-            = new SparseArray<Drawable.ConstantState>();
+    private static final LongSparseArray<Drawable.ConstantState> sPreloadedDrawables
+            = new LongSparseArray<Drawable.ConstantState>();
     private static final SparseArray<ColorStateList> mPreloadedColorStateLists
             = new SparseArray<ColorStateList>();
     private static boolean mPreloaded;
 
-    private final SparseArray<Drawable.ConstantState> mPreloadedDrawables;
+    private final LongSparseArray<Drawable.ConstantState> mPreloadedDrawables;
 
     /*package*/ final TypedValue mTmpValue = new TypedValue();
 
     // These are protected by the mTmpValue lock.
-    private final SparseArray<WeakReference<Drawable.ConstantState> > mDrawableCache
-            = new SparseArray<WeakReference<Drawable.ConstantState> >();
+    private final LongSparseArray<WeakReference<Drawable.ConstantState> > mDrawableCache
+            = new LongSparseArray<WeakReference<Drawable.ConstantState> >();
     private final SparseArray<WeakReference<ColorStateList> > mColorStateListCache
             = new SparseArray<WeakReference<ColorStateList> >();
     private boolean mPreloading;
@@ -89,20 +88,20 @@
     
     private final CompatibilityInfo mCompatibilityInfo;
 
-    private static final SparseArray<Object> EMPTY_ARRAY = new SparseArray<Object>() {
+    private static final LongSparseArray<Object> EMPTY_ARRAY = new LongSparseArray<Object>() {
         @Override
-        public void put(int k, Object o) {
+        public void put(long k, Object o) {
             throw new UnsupportedOperationException();
         }
         @Override
-        public void append(int k, Object o) {
+        public void append(long k, Object o) {
             throw new UnsupportedOperationException();
         }
     };
 
     @SuppressWarnings("unchecked")
-    private static <T> SparseArray<T> emptySparseArray() {
-        return (SparseArray<T>) EMPTY_ARRAY;
+    private static <T> LongSparseArray<T> emptySparseArray() {
+        return (LongSparseArray<T>) EMPTY_ARRAY;
     }
 
     /**
@@ -1315,14 +1314,14 @@
                                 configChanges, cs.getChangingConfigurations())) {
                             if (DEBUG_CONFIG) {
                                 Log.d(TAG, "FLUSHING #0x"
-                                        + Integer.toHexString(mDrawableCache.keyAt(i))
+                                        + Long.toHexString(mDrawableCache.keyAt(i))
                                         + " / " + cs + " with changes: 0x"
                                         + Integer.toHexString(cs.getChangingConfigurations()));
                             }
                             mDrawableCache.setValueAt(i, null);
                         } else if (DEBUG_CONFIG) {
                             Log.d(TAG, "(Keeping #0x"
-                                    + Integer.toHexString(mDrawableCache.keyAt(i))
+                                    + Long.toHexString(mDrawableCache.keyAt(i))
                                     + " / " + cs + " with changes: 0x"
                                     + Integer.toHexString(cs.getChangingConfigurations())
                                     + ")");
@@ -1653,7 +1652,7 @@
             }
         }
 
-        final int key = (value.assetCookie << 24) | value.data;
+        final long key = (((long) value.assetCookie) << 32) | value.data;
         Drawable dr = getCachedDrawable(key);
 
         if (dr != null) {
@@ -1733,7 +1732,7 @@
         return dr;
     }
 
-    private Drawable getCachedDrawable(int key) {
+    private Drawable getCachedDrawable(long key) {
         synchronized (mTmpValue) {
             WeakReference<Drawable.ConstantState> wr = mDrawableCache.get(key);
             if (wr != null) {   // we have the key
diff --git a/core/java/android/database/BulkCursorToCursorAdaptor.java b/core/java/android/database/BulkCursorToCursorAdaptor.java
index c26810a..cf30dd9 100644
--- a/core/java/android/database/BulkCursorToCursorAdaptor.java
+++ b/core/java/android/database/BulkCursorToCursorAdaptor.java
@@ -247,9 +247,11 @@
         try {
             return mBulkCursor.respond(extras);
         } catch (RemoteException e) {
-            // This should never happen because the system kills processes that are using remote
-            // cursors when the provider process is killed.
-            throw new RuntimeException(e);
+            // the system kills processes that are using remote cursors when the provider process
+            // is killed, but this can still happen if this is being called from the system process,
+            // so, better to log and return an empty bundle.
+            Log.w(TAG, "respond() threw RemoteException, returning an empty bundle.", e);
+            return Bundle.EMPTY;
         }
     }
 }
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 9c8c537..2490b8a 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -96,7 +96,7 @@
     public static final String[] HISTORY_PROJECTION = new String[] {
         BookmarkColumns._ID, BookmarkColumns.URL, BookmarkColumns.VISITS,
         BookmarkColumns.DATE, BookmarkColumns.BOOKMARK, BookmarkColumns.TITLE,
-        BookmarkColumns.FAVICON };
+        BookmarkColumns.FAVICON, BookmarkColumns.THUMBNAIL };
 
     /* these indices dependent on HISTORY_PROJECTION */
     public static final int HISTORY_PROJECTION_ID_INDEX = 0;
@@ -106,6 +106,10 @@
     public static final int HISTORY_PROJECTION_BOOKMARK_INDEX = 4;
     public static final int HISTORY_PROJECTION_TITLE_INDEX = 5;
     public static final int HISTORY_PROJECTION_FAVICON_INDEX = 6;
+    /**
+     * @hide
+     */
+    public static final int HISTORY_PROJECTION_THUMBNAIL_INDEX = 7;
 
     /* columns needed to determine whether to truncate history */
     public static final String[] TRUNCATE_HISTORY_PROJECTION = new String[] {
@@ -168,6 +172,7 @@
 
     /**
      *  Return a cursor pointing to a list of all the bookmarks.
+     *  Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS}
      *  @param cr   The ContentResolver used to access the database.
      */
     public static final Cursor getAllBookmarks(ContentResolver cr) throws 
@@ -179,6 +184,7 @@
 
     /**
      *  Return a cursor pointing to a list of all visited site urls.
+     *  Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS}
      *  @param cr   The ContentResolver used to access the database.
      */
     public static final Cursor getAllVisitedUrls(ContentResolver cr) throws
@@ -190,6 +196,8 @@
     /**
      *  Update the visited history to acknowledge that a site has been
      *  visited.
+     *  Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS}
+     *  Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS}
      *  @param cr   The ContentResolver used to access the database.
      *  @param url  The site being visited.
      *  @param real Whether this is an actual visit, and should be added to the
@@ -239,6 +247,8 @@
      * of them.  This is used to keep our history table to a
      * reasonable size.  Note: it does not prune bookmarks.  If the
      * user wants 1000 bookmarks, the user gets 1000 bookmarks.
+     *  Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS}
+     *  Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS}
      *
      * @param cr The ContentResolver used to access the database.
      */
@@ -272,6 +282,7 @@
 
     /**
      * Returns whether there is any history to clear.
+     *  Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS}
      * @param cr   The ContentResolver used to access the database.
      * @return boolean  True if the history can be cleared.
      */
@@ -297,6 +308,7 @@
     /**
      *  Delete all entries from the bookmarks/history table which are
      *  not bookmarks.  Also set all visited bookmarks to unvisited.
+     *  Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS}
      *  @param cr   The ContentResolver used to access the database.
      */
     public static final void clearHistory(ContentResolver cr) {
@@ -306,6 +318,8 @@
     /**
      * Helper function to delete all history items and revert all
      * bookmarks to zero visits which meet the criteria provided.
+     *  Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS}
+     *  Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS}
      * @param cr   The ContentResolver used to access the database.
      * @param whereClause   String to limit the items affected.
      *                      null means all items.
@@ -368,6 +382,7 @@
 
     /**
      * Delete all history items from begin to end.
+     *  Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS}
      * @param cr    The ContentResolver used to access the database.
      * @param begin First date to remove.  If -1, all dates before end.
      *              Inclusive.
@@ -395,6 +410,7 @@
 
     /**
      * Remove a specific url from the history database.
+     *  Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS}
      * @param cr    The ContentResolver used to access the database.
      * @param url   url to remove.
      */
@@ -408,6 +424,8 @@
 
     /**
      * Add a search string to the searches database.
+     *  Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS}
+     *  Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS}
      * @param cr   The ContentResolver used to access the database.
      * @param search    The string to add to the searches database.
      */
@@ -437,6 +455,7 @@
     }
     /**
      * Remove all searches from the search database.
+     *  Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS}
      * @param cr   The ContentResolver used to access the database.
      */
     public static final void clearSearches(ContentResolver cr) {
@@ -451,6 +470,7 @@
     
     /**
      *  Request all icons from the database.
+     *  Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS}
      *  @param  cr The ContentResolver used to access the database.
      *  @param  where Clause to be used to limit the query from the database.
      *          Must be an allowable string to be passed into a database query.
@@ -486,6 +506,10 @@
         public static final String TITLE = "title";
         public static final String CREATED = "created";
         public static final String FAVICON = "favicon";
+        /**
+         * @hide
+         */
+        public static final String THUMBNAIL = "thumbnail";
     }
 
     public static class SearchColumns implements BaseColumns {
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index 0829cfb..5f84e57 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -40,7 +40,7 @@
  */
 public class Contacts {
     private static final String TAG = "Contacts";
-    
+
     public static final String AUTHORITY = "contacts";
 
     /**
@@ -191,7 +191,7 @@
          * <p>Type: TEXT</P>
          */
         public static final String PHONETIC_NAME = "phonetic_name";
-        
+
         /**
          * The display name. If name is not null name, else if number is not null number,
          * else if email is not null email.
@@ -206,7 +206,7 @@
          * @hide Used only in Contacts application for now.
          */
         public static final String SORT_STRING = "sort_string";
-        
+
         /**
          * Notes about the person.
          * <P>Type: TEXT</P>
@@ -248,7 +248,7 @@
          * The server version of the photo
          * <P>Type: TEXT (the version number portion of the photo URI)</P>
          */
-        public static final String PHOTO_VERSION = "photo_version";       
+        public static final String PHOTO_VERSION = "photo_version";
     }
 
     /**
@@ -287,14 +287,14 @@
          * additional path segment after this URI. This matches any people with
          * at least one E-mail or IM {@link ContactMethods} that match the
          * filter.
-         * 
+         *
          * Not exposed because we expect significant changes in the contacts
          * schema and do not want to have to support this.
          * @hide
          */
         public static final Uri WITH_EMAIL_OR_IM_FILTER_URI =
             Uri.parse("content://contacts/people/with_email_or_im_filter");
-        
+
         /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of
          * people.
@@ -379,13 +379,13 @@
             if (groupId == 0) {
                 throw new IllegalStateException("Failed to find the My Contacts group");
             }
-            
+
             return addToGroup(resolver, personId, groupId);
         }
 
         /**
          * Adds a person to a group referred to by name.
-         * 
+         *
          * @param resolver the resolver to use
          * @param personId the person to add to the group
          * @param groupName the name of the group to add the contact to
@@ -409,13 +409,13 @@
             if (groupId == 0) {
                 throw new IllegalStateException("Failed to find the My Contacts group");
             }
-            
+
             return addToGroup(resolver, personId, groupId);
         }
 
         /**
          * Adds a person to a group.
-         * 
+         *
          * @param resolver the resolver to use
          * @param personId the person to add to the group
          * @param groupId the group to add the person to
@@ -427,14 +427,14 @@
             values.put(GroupMembership.GROUP_ID, groupId);
             return resolver.insert(GroupMembership.CONTENT_URI, values);
         }
-        
+
         private static final String[] GROUPS_PROJECTION = new String[] {
             Groups._ID,
         };
 
         /**
          * Creates a new contacts and adds it to the "My Contacts" group.
-         * 
+         *
          * @param resolver the ContentResolver to use
          * @param values the values to use when creating the contact
          * @return the URI of the contact, or null if the operation fails
@@ -472,7 +472,7 @@
             values.put(Photos.DATA, data);
             cr.update(photoUri, values, null, null);
         }
-        
+
         /**
          * Opens an InputStream for the person's photo and returns the photo as a Bitmap.
          * If the person's photo isn't present returns the placeholderImageResource instead.
@@ -739,7 +739,7 @@
             CharSequence display = "";
 
             if (type != People.Phones.TYPE_CUSTOM) {
-                CharSequence[] labels = labelArray != null? labelArray 
+                CharSequence[] labels = labelArray != null? labelArray
                         : context.getResources().getTextArray(
                                 com.android.internal.R.array.phoneTypes);
                 try {
@@ -759,7 +759,7 @@
                 CharSequence label) {
             return getDisplayLabel(context, type, label, null);
         }
-        
+
         /**
          * The content:// style URL for this table
          */
@@ -984,7 +984,7 @@
             throw new IllegalArgumentException(
                     "the value is not a valid encoded protocol, " + encodedString);
         }
-        
+
         /**
          * This looks up the provider name defined in
          * {@link android.provider.Im.ProviderNames} from the predefined IM protocol id.
@@ -1197,7 +1197,7 @@
 
         /**
          * Gets the resource ID for the proper presence icon.
-         * 
+         *
          * @param status the status to get the icon for
          * @return the resource ID for the proper presence icon
          */
@@ -1205,17 +1205,17 @@
             switch (status) {
                 case Contacts.People.AVAILABLE:
                     return com.android.internal.R.drawable.presence_online;
-    
+
                 case Contacts.People.IDLE:
                 case Contacts.People.AWAY:
                     return com.android.internal.R.drawable.presence_away;
-    
+
                 case Contacts.People.DO_NOT_DISTURB:
                     return com.android.internal.R.drawable.presence_busy;
-    
+
                 case Contacts.People.INVISIBLE:
                     return com.android.internal.R.drawable.presence_invisible;
-                    
+
                 case Contacts.People.OFFLINE:
                 default:
                     return com.android.internal.R.drawable.presence_offline;
@@ -1455,28 +1455,27 @@
          * This is the intent that is fired when a search suggestion is clicked on.
          */
         public static final String SEARCH_SUGGESTION_CLICKED =
-                "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
+                ContactsContract.Intents.SEARCH_SUGGESTION_CLICKED;
 
         /**
-         * This is the intent that is fired when a search suggestion for dialing a number 
+         * This is the intent that is fired when a search suggestion for dialing a number
          * is clicked on.
          */
         public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED =
-                "android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED";
+                ContactsContract.Intents.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED;
 
         /**
          * This is the intent that is fired when a search suggestion for creating a contact
          * is clicked on.
          */
         public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED =
-                "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
+                ContactsContract.Intents.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED;
 
         /**
          * Starts an Activity that lets the user pick a contact to attach an image to.
          * After picking the contact it launches the image cropper in face detection mode.
          */
-        public static final String ATTACH_IMAGE =
-                "com.android.contacts.action.ATTACH_IMAGE";
+        public static final String ATTACH_IMAGE = ContactsContract.Intents.ATTACH_IMAGE;
 
         /**
          * Takes as input a data URI with a mailto: or tel: scheme. If a single
@@ -1502,7 +1501,7 @@
          * prompting the user when the contact doesn't exist.
          */
         public static final String SHOW_OR_CREATE_CONTACT =
-                "com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
+                ContactsContract.Intents.SHOW_OR_CREATE_CONTACT;
 
         /**
          * Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new
@@ -1511,9 +1510,8 @@
          * <p>
          * Type: BOOLEAN
          */
-        public static final String EXTRA_FORCE_CREATE =
-                "com.android.contacts.action.FORCE_CREATE";
-        
+        public static final String EXTRA_FORCE_CREATE = ContactsContract.Intents.EXTRA_FORCE_CREATE;
+
         /**
          * Used with {@link #SHOW_OR_CREATE_CONTACT} to specify an exact
          * description to be shown when prompting user about creating a new
@@ -1522,7 +1520,7 @@
          * Type: STRING
          */
         public static final String EXTRA_CREATE_DESCRIPTION =
-            "com.android.contacts.action.CREATE_DESCRIPTION";
+                ContactsContract.Intents.EXTRA_CREATE_DESCRIPTION;
 
         /**
          * Intents related to the Contacts app UI.
@@ -1531,43 +1529,42 @@
             /**
              * The action for the default contacts list tab.
              */
-            public static final String LIST_DEFAULT =
-                    "com.android.contacts.action.LIST_DEFAULT";
+            public static final String LIST_DEFAULT = ContactsContract.Intents.UI.LIST_DEFAULT;
 
             /**
              * The action for the contacts list tab.
              */
             public static final String LIST_GROUP_ACTION =
-                    "com.android.contacts.action.LIST_GROUP";
+                    ContactsContract.Intents.UI.LIST_GROUP_ACTION;
 
             /**
              * When in LIST_GROUP_ACTION mode, this is the group to display.
              */
-            public static final String GROUP_NAME_EXTRA_KEY = "com.android.contacts.extra.GROUP";
-            
+            public static final String GROUP_NAME_EXTRA_KEY =
+                    ContactsContract.Intents.UI.GROUP_NAME_EXTRA_KEY;
             /**
              * The action for the all contacts list tab.
              */
             public static final String LIST_ALL_CONTACTS_ACTION =
-                    "com.android.contacts.action.LIST_ALL_CONTACTS";
+                    ContactsContract.Intents.UI.LIST_ALL_CONTACTS_ACTION;
 
             /**
              * The action for the contacts with phone numbers list tab.
              */
             public static final String LIST_CONTACTS_WITH_PHONES_ACTION =
-                    "com.android.contacts.action.LIST_CONTACTS_WITH_PHONES";
+                    ContactsContract.Intents.UI.LIST_CONTACTS_WITH_PHONES_ACTION;
 
             /**
              * The action for the starred contacts list tab.
              */
             public static final String LIST_STARRED_ACTION =
-                    "com.android.contacts.action.LIST_STARRED";
+                    ContactsContract.Intents.UI.LIST_STARRED_ACTION;
 
             /**
              * The action for the frequent contacts list tab.
              */
             public static final String LIST_FREQUENT_ACTION =
-                    "com.android.contacts.action.LIST_FREQUENT";
+                    ContactsContract.Intents.UI.LIST_FREQUENT_ACTION;
 
             /**
              * The action for the "strequent" contacts list tab. It first lists the starred
@@ -1575,15 +1572,15 @@
              * order of the number of times they have been contacted.
              */
             public static final String LIST_STREQUENT_ACTION =
-                    "com.android.contacts.action.LIST_STREQUENT";
+                    ContactsContract.Intents.UI.LIST_STREQUENT_ACTION;
 
             /**
              * A key for to be used as an intent extra to set the activity
              * title to a custom String value.
              */
             public static final String TITLE_EXTRA_KEY =
-                "com.android.contacts.extra.TITLE_EXTRA";
-            
+                    ContactsContract.Intents.UI.TITLE_EXTRA_KEY;
+
             /**
              * Activity Action: Display a filtered list of contacts
              * <p>
@@ -1592,15 +1589,15 @@
              * <p>
              * Output: Nothing.
              */
-            public static final String FILTER_CONTACTS_ACTION = 
-                "com.android.contacts.action.FILTER_CONTACTS";
-            
+            public static final String FILTER_CONTACTS_ACTION =
+                    ContactsContract.Intents.UI.FILTER_CONTACTS_ACTION;
+
             /**
              * Used as an int extra field in {@link #FILTER_CONTACTS_ACTION}
              * intents to supply the text on which to filter.
              */
-            public static final String FILTER_TEXT_EXTRA_KEY = 
-                "com.android.contacts.extra.FILTER_TEXT";
+            public static final String FILTER_TEXT_EXTRA_KEY =
+                    ContactsContract.Intents.UI.FILTER_TEXT_EXTRA_KEY;
         }
 
         /**
@@ -1609,170 +1606,179 @@
          */
         public static final class Insert {
             /** The action code to use when adding a contact */
-            public static final String ACTION = Intent.ACTION_INSERT;
-
+            public static final String ACTION = ContactsContract.Intents.Insert.ACTION;
             /**
              * If present, forces a bypass of quick insert mode.
              */
-            public static final String FULL_MODE = "full_mode";
-
+            public static final String FULL_MODE = ContactsContract.Intents.Insert.FULL_MODE;
             /**
              * The extra field for the contact name.
              * <P>Type: String</P>
              */
-            public static final String NAME = "name";
+            public static final String NAME = ContactsContract.Intents.Insert.NAME;
 
             /**
              * The extra field for the contact phonetic name.
              * <P>Type: String</P>
              */
-            public static final String PHONETIC_NAME = "phonetic_name";
+            public static final String PHONETIC_NAME =
+                    ContactsContract.Intents.Insert.PHONETIC_NAME;
 
             /**
              * The extra field for the contact company.
              * <P>Type: String</P>
              */
-            public static final String COMPANY = "company";
+            public static final String COMPANY = ContactsContract.Intents.Insert.COMPANY;
 
             /**
              * The extra field for the contact job title.
              * <P>Type: String</P>
              */
-            public static final String JOB_TITLE = "job_title";
+            public static final String JOB_TITLE = ContactsContract.Intents.Insert.JOB_TITLE;
 
             /**
              * The extra field for the contact notes.
              * <P>Type: String</P>
              */
-            public static final String NOTES = "notes";
+            public static final String NOTES = ContactsContract.Intents.Insert.NOTES;
 
             /**
              * The extra field for the contact phone number.
              * <P>Type: String</P>
              */
-            public static final String PHONE = "phone";
+            public static final String PHONE = ContactsContract.Intents.Insert.PHONE;
 
             /**
              * The extra field for the contact phone number type.
              * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
              *  or a string specifying a custom label.</P>
              */
-            public static final String PHONE_TYPE = "phone_type";
+            public static final String PHONE_TYPE = ContactsContract.Intents.Insert.PHONE_TYPE;
 
             /**
              * The extra field for the phone isprimary flag.
              * <P>Type: boolean</P>
              */
-            public static final String PHONE_ISPRIMARY = "phone_isprimary";
+            public static final String PHONE_ISPRIMARY =
+                    ContactsContract.Intents.Insert.PHONE_ISPRIMARY;
 
             /**
              * The extra field for an optional second contact phone number.
              * <P>Type: String</P>
              */
-            public static final String SECONDARY_PHONE = "secondary_phone";
+            public static final String SECONDARY_PHONE =
+                    ContactsContract.Intents.Insert.SECONDARY_PHONE;
 
             /**
              * The extra field for an optional second contact phone number type.
              * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
              *  or a string specifying a custom label.</P>
              */
-            public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type";
+            public static final String SECONDARY_PHONE_TYPE =
+                    ContactsContract.Intents.Insert.SECONDARY_PHONE_TYPE;
 
             /**
              * The extra field for an optional third contact phone number.
              * <P>Type: String</P>
              */
-            public static final String TERTIARY_PHONE = "tertiary_phone";
+            public static final String TERTIARY_PHONE =
+                    ContactsContract.Intents.Insert.TERTIARY_PHONE;
 
             /**
              * The extra field for an optional third contact phone number type.
              * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
              *  or a string specifying a custom label.</P>
              */
-            public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
+            public static final String TERTIARY_PHONE_TYPE =
+                    ContactsContract.Intents.Insert.TERTIARY_PHONE_TYPE;
 
             /**
              * The extra field for the contact email address.
              * <P>Type: String</P>
              */
-            public static final String EMAIL = "email";
+            public static final String EMAIL = ContactsContract.Intents.Insert.EMAIL;
 
             /**
              * The extra field for the contact email type.
              * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
              *  or a string specifying a custom label.</P>
              */
-            public static final String EMAIL_TYPE = "email_type";
+            public static final String EMAIL_TYPE = ContactsContract.Intents.Insert.EMAIL_TYPE;
 
             /**
              * The extra field for the email isprimary flag.
              * <P>Type: boolean</P>
              */
-            public static final String EMAIL_ISPRIMARY = "email_isprimary";
+            public static final String EMAIL_ISPRIMARY =
+                    ContactsContract.Intents.Insert.EMAIL_ISPRIMARY;
 
             /**
              * The extra field for an optional second contact email address.
              * <P>Type: String</P>
              */
-            public static final String SECONDARY_EMAIL = "secondary_email";
+            public static final String SECONDARY_EMAIL =
+                    ContactsContract.Intents.Insert.SECONDARY_EMAIL;
 
             /**
              * The extra field for an optional second contact email type.
              * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
              *  or a string specifying a custom label.</P>
              */
-            public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type";
+            public static final String SECONDARY_EMAIL_TYPE =
+                    ContactsContract.Intents.Insert.SECONDARY_EMAIL_TYPE;
 
             /**
              * The extra field for an optional third contact email address.
              * <P>Type: String</P>
              */
-            public static final String TERTIARY_EMAIL = "tertiary_email";
+            public static final String TERTIARY_EMAIL =
+                    ContactsContract.Intents.Insert.TERTIARY_EMAIL;
 
             /**
              * The extra field for an optional third contact email type.
              * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
              *  or a string specifying a custom label.</P>
              */
-            public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
+            public static final String TERTIARY_EMAIL_TYPE =
+                    ContactsContract.Intents.Insert.TERTIARY_EMAIL_TYPE;
 
             /**
              * The extra field for the contact postal address.
              * <P>Type: String</P>
              */
-            public static final String POSTAL = "postal";
+            public static final String POSTAL = ContactsContract.Intents.Insert.POSTAL;
 
             /**
              * The extra field for the contact postal address type.
              * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
              *  or a string specifying a custom label.</P>
              */
-            public static final String POSTAL_TYPE = "postal_type";
+            public static final String POSTAL_TYPE = ContactsContract.Intents.Insert.POSTAL_TYPE;
 
             /**
              * The extra field for the postal isprimary flag.
              * <P>Type: boolean</P>
              */
-            public static final String POSTAL_ISPRIMARY = "postal_isprimary";
+            public static final String POSTAL_ISPRIMARY = ContactsContract.Intents.Insert.POSTAL_ISPRIMARY;
 
             /**
              * The extra field for an IM handle.
              * <P>Type: String</P>
              */
-            public static final String IM_HANDLE = "im_handle";
+            public static final String IM_HANDLE = ContactsContract.Intents.Insert.IM_HANDLE;
 
             /**
              * The extra field for the IM protocol
              * <P>Type: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol}
              * or {@link Contacts.ContactMethods#encodeCustomImProtocol}.</P>
              */
-            public static final String IM_PROTOCOL = "im_protocol";
+            public static final String IM_PROTOCOL = ContactsContract.Intents.Insert.IM_PROTOCOL;
 
             /**
              * The extra field for the IM isprimary flag.
              * <P>Type: boolean</P>
              */
-            public static final String IM_ISPRIMARY = "im_isprimary";
+            public static final String IM_ISPRIMARY = ContactsContract.Intents.Insert.IM_ISPRIMARY;
         }
     }
 }
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index d98842e..48dc3ae 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -16,6 +16,7 @@
 
 package android.provider;
 
+import android.content.Intent;
 import android.graphics.BitmapFactory;
 import android.net.Uri;
 
@@ -179,6 +180,21 @@
          */
         public static final Uri CONTENT_SUMMARY_FILTER_URI = Uri.withAppendedPath(
                 CONTENT_SUMMARY_URI, "filter");
+        /**
+         * The content:// style URI for this table joined with useful data from
+         * {@link Data} and {@link Presence}, filtered to include only starred aggregates
+         * and the most frequently contacted aggregates.
+         */
+        public static final Uri CONTENT_SUMMARY_STREQUENT_URI = Uri.withAppendedPath(
+                CONTENT_SUMMARY_URI, "strequent");
+        /**
+         * The content:// style URI used for "type-to-filter" functionality on the
+         * {@link CONTENT_SUMMARY_STREQUENT_URI} URI. The filter string will be used to match
+         * various parts of the aggregate name. The filter argument should be passed
+         * as an additional path segment after this URI.
+         */
+        public static final Uri CONTENT_SUMMARY_STREQUENT_FILTER_URI = Uri.withAppendedPath(
+                CONTENT_SUMMARY_STREQUENT_URI, "filter");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of
@@ -266,7 +282,8 @@
          *
          * @hide
          */
-        public static final Uri CONTENT_FILTER_EMAIL_URI = Uri.withAppendedPath(CONTENT_URI, "filter_email");
+        public static final Uri CONTENT_FILTER_EMAIL_URI =
+                Uri.withAppendedPath(CONTENT_URI, "filter_email");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of
@@ -1056,4 +1073,344 @@
         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
                 "restriction_exceptions");
     }
+
+    /**
+     * Contains helper classes used to create or manage {@link android.content.Intent Intents}
+     * that involve contacts.
+     */
+    public static final class Intents {
+        /**
+         * This is the intent that is fired when a search suggestion is clicked on.
+         */
+        public static final String SEARCH_SUGGESTION_CLICKED =
+                "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
+
+        /**
+         * This is the intent that is fired when a search suggestion for dialing a number
+         * is clicked on.
+         */
+        public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED =
+                "android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED";
+
+        /**
+         * This is the intent that is fired when a search suggestion for creating a contact
+         * is clicked on.
+         */
+        public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED =
+                "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
+
+        /**
+         * Starts an Activity that lets the user pick a contact to attach an image to.
+         * After picking the contact it launches the image cropper in face detection mode.
+         */
+        public static final String ATTACH_IMAGE =
+                "com.android.contacts.action.ATTACH_IMAGE";
+
+        /**
+         * Takes as input a data URI with a mailto: or tel: scheme. If a single
+         * contact exists with the given data it will be shown. If no contact
+         * exists, a dialog will ask the user if they want to create a new
+         * contact with the provided details filled in. If multiple contacts
+         * share the data the user will be prompted to pick which contact they
+         * want to view.
+         * <p>
+         * For <code>mailto:</code> URIs, the scheme specific portion must be a
+         * raw email address, such as one built using
+         * {@link Uri#fromParts(String, String, String)}.
+         * <p>
+         * For <code>tel:</code> URIs, the scheme specific portion is compared
+         * to existing numbers using the standard caller ID lookup algorithm.
+         * The number must be properly encoded, for example using
+         * {@link Uri#fromParts(String, String, String)}.
+         * <p>
+         * Any extras from the {@link Insert} class will be passed along to the
+         * create activity if there are no contacts to show.
+         * <p>
+         * Passing true for the {@link #EXTRA_FORCE_CREATE} extra will skip
+         * prompting the user when the contact doesn't exist.
+         */
+        public static final String SHOW_OR_CREATE_CONTACT =
+                "com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
+
+        /**
+         * Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new
+         * contact if no matching contact found. Otherwise, default behavior is
+         * to prompt user with dialog before creating.
+         * <p>
+         * Type: BOOLEAN
+         */
+        public static final String EXTRA_FORCE_CREATE =
+                "com.android.contacts.action.FORCE_CREATE";
+
+        /**
+         * Used with {@link #SHOW_OR_CREATE_CONTACT} to specify an exact
+         * description to be shown when prompting user about creating a new
+         * contact.
+         * <p>
+         * Type: STRING
+         */
+        public static final String EXTRA_CREATE_DESCRIPTION =
+            "com.android.contacts.action.CREATE_DESCRIPTION";
+
+        /**
+         * Intents related to the Contacts app UI.
+         */
+        public static final class UI {
+            /**
+             * The action for the default contacts list tab.
+             */
+            public static final String LIST_DEFAULT =
+                    "com.android.contacts.action.LIST_DEFAULT";
+
+            /**
+             * The action for the contacts list tab.
+             */
+            public static final String LIST_GROUP_ACTION =
+                    "com.android.contacts.action.LIST_GROUP";
+
+            /**
+             * When in LIST_GROUP_ACTION mode, this is the group to display.
+             */
+            public static final String GROUP_NAME_EXTRA_KEY = "com.android.contacts.extra.GROUP";
+
+            /**
+             * The action for the all contacts list tab.
+             */
+            public static final String LIST_ALL_CONTACTS_ACTION =
+                    "com.android.contacts.action.LIST_ALL_CONTACTS";
+
+            /**
+             * The action for the contacts with phone numbers list tab.
+             */
+            public static final String LIST_CONTACTS_WITH_PHONES_ACTION =
+                    "com.android.contacts.action.LIST_CONTACTS_WITH_PHONES";
+
+            /**
+             * The action for the starred contacts list tab.
+             */
+            public static final String LIST_STARRED_ACTION =
+                    "com.android.contacts.action.LIST_STARRED";
+
+            /**
+             * The action for the frequent contacts list tab.
+             */
+            public static final String LIST_FREQUENT_ACTION =
+                    "com.android.contacts.action.LIST_FREQUENT";
+
+            /**
+             * The action for the "strequent" contacts list tab. It first lists the starred
+             * contacts in alphabetical order and then the frequent contacts in descending
+             * order of the number of times they have been contacted.
+             */
+            public static final String LIST_STREQUENT_ACTION =
+                    "com.android.contacts.action.LIST_STREQUENT";
+
+            /**
+             * A key for to be used as an intent extra to set the activity
+             * title to a custom String value.
+             */
+            public static final String TITLE_EXTRA_KEY =
+                "com.android.contacts.extra.TITLE_EXTRA";
+
+            /**
+             * Activity Action: Display a filtered list of contacts
+             * <p>
+             * Input: Extra field {@link #FILTER_TEXT_EXTRA_KEY} is the text to use for
+             * filtering
+             * <p>
+             * Output: Nothing.
+             */
+            public static final String FILTER_CONTACTS_ACTION =
+                "com.android.contacts.action.FILTER_CONTACTS";
+
+            /**
+             * Used as an int extra field in {@link #FILTER_CONTACTS_ACTION}
+             * intents to supply the text on which to filter.
+             */
+            public static final String FILTER_TEXT_EXTRA_KEY =
+                "com.android.contacts.extra.FILTER_TEXT";
+        }
+
+        /**
+         * Convenience class that contains string constants used
+         * to create contact {@link android.content.Intent Intents}.
+         */
+        public static final class Insert {
+            /** The action code to use when adding a contact */
+            public static final String ACTION = Intent.ACTION_INSERT;
+
+            /**
+             * If present, forces a bypass of quick insert mode.
+             */
+            public static final String FULL_MODE = "full_mode";
+
+            /**
+             * The extra field for the contact name.
+             * <P>Type: String</P>
+             */
+            public static final String NAME = "name";
+
+            // TODO add structured name values here.
+
+            /**
+             * The extra field for the contact phonetic name.
+             * <P>Type: String</P>
+             */
+            public static final String PHONETIC_NAME = "phonetic_name";
+
+            /**
+             * The extra field for the contact company.
+             * <P>Type: String</P>
+             */
+            public static final String COMPANY = "company";
+
+            /**
+             * The extra field for the contact job title.
+             * <P>Type: String</P>
+             */
+            public static final String JOB_TITLE = "job_title";
+
+            /**
+             * The extra field for the contact notes.
+             * <P>Type: String</P>
+             */
+            public static final String NOTES = "notes";
+
+            /**
+             * The extra field for the contact phone number.
+             * <P>Type: String</P>
+             */
+            public static final String PHONE = "phone";
+
+            /**
+             * The extra field for the contact phone number type.
+             * <P>Type: Either an integer value from
+             * {@link android.provider.Contacts.PhonesColumns PhonesColumns},
+             *  or a string specifying a custom label.</P>
+             */
+            public static final String PHONE_TYPE = "phone_type";
+
+            /**
+             * The extra field for the phone isprimary flag.
+             * <P>Type: boolean</P>
+             */
+            public static final String PHONE_ISPRIMARY = "phone_isprimary";
+
+            /**
+             * The extra field for an optional second contact phone number.
+             * <P>Type: String</P>
+             */
+            public static final String SECONDARY_PHONE = "secondary_phone";
+
+            /**
+             * The extra field for an optional second contact phone number type.
+             * <P>Type: Either an integer value from
+             * {@link android.provider.Contacts.PhonesColumns PhonesColumns},
+             *  or a string specifying a custom label.</P>
+             */
+            public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type";
+
+            /**
+             * The extra field for an optional third contact phone number.
+             * <P>Type: String</P>
+             */
+            public static final String TERTIARY_PHONE = "tertiary_phone";
+
+            /**
+             * The extra field for an optional third contact phone number type.
+             * <P>Type: Either an integer value from
+             * {@link android.provider.Contacts.PhonesColumns PhonesColumns},
+             *  or a string specifying a custom label.</P>
+             */
+            public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
+
+            /**
+             * The extra field for the contact email address.
+             * <P>Type: String</P>
+             */
+            public static final String EMAIL = "email";
+
+            /**
+             * The extra field for the contact email type.
+             * <P>Type: Either an integer value from
+             * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+             *  or a string specifying a custom label.</P>
+             */
+            public static final String EMAIL_TYPE = "email_type";
+
+            /**
+             * The extra field for the email isprimary flag.
+             * <P>Type: boolean</P>
+             */
+            public static final String EMAIL_ISPRIMARY = "email_isprimary";
+
+            /**
+             * The extra field for an optional second contact email address.
+             * <P>Type: String</P>
+             */
+            public static final String SECONDARY_EMAIL = "secondary_email";
+
+            /**
+             * The extra field for an optional second contact email type.
+             * <P>Type: Either an integer value from
+             * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+             *  or a string specifying a custom label.</P>
+             */
+            public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type";
+
+            /**
+             * The extra field for an optional third contact email address.
+             * <P>Type: String</P>
+             */
+            public static final String TERTIARY_EMAIL = "tertiary_email";
+
+            /**
+             * The extra field for an optional third contact email type.
+             * <P>Type: Either an integer value from
+             * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+             *  or a string specifying a custom label.</P>
+             */
+            public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
+
+            /**
+             * The extra field for the contact postal address.
+             * <P>Type: String</P>
+             */
+            public static final String POSTAL = "postal";
+
+            /**
+             * The extra field for the contact postal address type.
+             * <P>Type: Either an integer value from
+             * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+             *  or a string specifying a custom label.</P>
+             */
+            public static final String POSTAL_TYPE = "postal_type";
+
+            /**
+             * The extra field for the postal isprimary flag.
+             * <P>Type: boolean</P>
+             */
+            public static final String POSTAL_ISPRIMARY = "postal_isprimary";
+
+            /**
+             * The extra field for an IM handle.
+             * <P>Type: String</P>
+             */
+            public static final String IM_HANDLE = "im_handle";
+
+            /**
+             * The extra field for the IM protocol
+             * <P>Type: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol}
+             * or {@link Contacts.ContactMethods#encodeCustomImProtocol}.</P>
+             */
+            public static final String IM_PROTOCOL = "im_protocol";
+
+            /**
+             * The extra field for the IM isprimary flag.
+             * <P>Type: boolean</P>
+             */
+            public static final String IM_ISPRIMARY = "im_isprimary";
+        }
+    }
+
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 03c7f28..ebe54fcd 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1976,6 +1976,16 @@
         public static final String TTS_DEFAULT_LANG = "tts_default_lang";
 
         /**
+         * Default text-to-speech country.
+         */
+        public static final String TTS_DEFAULT_COUNTRY = "tts_default_country";
+
+        /**
+         * Default text-to-speech locale variant.
+         */
+        public static final String TTS_DEFAULT_VARIANT = "tts_default_variant";
+
+        /**
          * Whether to notify the user of open networks.
          * <p>
          * If not connected and the scan results have an open network, we will
@@ -2180,6 +2190,14 @@
         public static final String TTY_MODE_ENABLED = "tty_mode_enabled";
 
         /**
+         * Flag for allowing service provider to use location information to improve products and
+         * services.
+         * Type: int ( 0 = disallow, 1 = allow )
+         * @hide
+         */
+        public static final String USE_LOCATION_FOR_SERVICES = "use_location";
+
+        /**
          * Helper method for determining if a location provider is enabled.
          * @param cr the content resolver to use
          * @param provider the location provider to query
@@ -2527,6 +2545,16 @@
         public static final String GMAIL_DISCARD_ERROR_UPHILL_OP = "gmail_discard_error_uphill_op";
 
         /**
+         * the transcoder URL for mobile devices.
+         */
+        public static final String TRANSCODER_URL = "mobile_transcoder_url";
+
+        /**
+         * URL that points to the privacy terms of the Google Talk service.
+         */
+        public static final String GTALK_TERMS_OF_SERVICE_URL = "gtalk_terms_of_service_url";
+
+        /**
          * Hostname of the GTalk server.
          */
         public static final String GTALK_SERVICE_HOSTNAME = "gtalk_hostname";
@@ -2623,26 +2651,6 @@
                 "gtalk_wifi_max_heartbeat_ping_interval_ms";
 
         /**
-         * The minimum interval for how frequently we send heartbeat pings to the GTalk server.
-         */
-        public static final String GTALK_SERVICE_MIN_HEARTBEAT_INTERVAL_MS =
-                "gtalk_min_heartbeat_ping_interval_ms";
-
-        /**
-         * The scale down factor used by adaptive heartbeat logic (to scale down the heartbeat
-         * interval) when the previous interval fails to get a response from the server.
-         */
-        public static final String GTALK_SERVICE_ADAPTIVE_HEARTBEAT_SCALER =
-                "gtalk_adaptive_heartbeat_scaler";
-
-        /**
-         * The trigger for adaptively scaling down the heartbeat interval. This is the number of
-         * consecutive times we failed to get a server response for sending the heartbeat ping.
-         */
-        public static final String GTALK_SERVICE_ADAPTIVE_HEARTBEAT_TRIGGER =
-                "gtalk_adaptive_heartbeat_trigger";
-
-        /**
          * How long we wait to receive a heartbeat ping acknowledgement (or another packet)
          * from the GTalk server, before deeming the connection dead.
          */
@@ -2695,6 +2703,15 @@
         public static final String GTALK_USE_BARE_JID_TIMEOUT_MS = "gtalk_use_barejid_timeout_ms";
 
         /**
+         * This is the threshold of retry number when there is an authentication expired failure
+         * for Google Talk. In some situation, e.g. when a Google Apps account is disabled chat
+         * service, the connection keeps failing. This threshold controls when we should stop
+         * the retrying.
+         */
+        public static final String GTALK_MAX_RETRIES_FOR_AUTH_EXPIRED =
+            "gtalk_max_retries_for_auth_expired";
+
+        /**
          * Enable use of ssl session caching.
          * 'db' - save each session in a (per process) database
          * 'file' - save each session in a (per process) file
@@ -2791,6 +2808,13 @@
         public static final String VENDING_TAB_2_TITLE = "vending_tab_2_title";
 
         /**
+         * Frequency in milliseconds at which we should request MCS heartbeats
+         * from the Vending Machine client.
+         */
+        public static final String VENDING_HEARTBEAT_FREQUENCY_MS =
+                "vending_heartbeat_frequency_ms";
+
+        /**
          * URL that points to the legal terms of service to display in Settings.
          * <p>
          * This should be a https URL. For a pretty user-friendly URL, use
@@ -3094,6 +3118,7 @@
          * Flag for allowing service provider to use location information to improve products and
          * services.
          * Type: int ( 0 = disallow, 1 = allow )
+         * @deprecated
          */
         public static final String USE_LOCATION_FOR_SERVICES = "use_location";
 
diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothDeviceService.java
index 36c432b..75c590d 100644
--- a/core/java/android/server/BluetoothDeviceService.java
+++ b/core/java/android/server/BluetoothDeviceService.java
@@ -809,7 +809,16 @@
     }
 
     /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) {
-        Map<String, String> propertyValues = new HashMap<String, String>();
+        /*
+         * We get a DeviceFound signal every time RSSI changes or name changes.
+         * Don't create a new Map object every time */
+        Map<String, String> propertyValues = mRemoteDeviceProperties.get(address);
+        if (propertyValues != null) {
+            propertyValues.clear();
+        } else {
+            propertyValues = new HashMap<String, String>();
+        }
+
         for (int i = 0; i < properties.length; i+=2) {
             String value = null;
             if (propertyValues.containsKey(properties[i])) {
@@ -1039,6 +1048,8 @@
             break;
         }
         pw.println("getHeadsetAddress() = " + headset.getHeadsetAddress());
+        pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
+
         headset.close();
     }
 
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 00c13b7..ed66dce 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -130,12 +130,14 @@
         mBluetoothService.addRemoteDeviceProperties(address, properties);
         String rssi = mBluetoothService.getRemoteDeviceProperty(address, "RSSI");
         String classValue = mBluetoothService.getRemoteDeviceProperty(address, "Class");
+        String name = mBluetoothService.getRemoteDeviceProperty(address, "Name");
 
         if (rssi != null && classValue != null) {
             Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION);
             intent.putExtra(BluetoothIntent.ADDRESS, address);
-            intent.putExtra(BluetoothIntent.CLASS, classValue);
+            intent.putExtra(BluetoothIntent.CLASS, Integer.valueOf(classValue));
             intent.putExtra(BluetoothIntent.RSSI, (short)Integer.valueOf(rssi).intValue());
+            intent.putExtra(BluetoothIntent.NAME, name);
 
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
         } else {
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 8f58194..9fc143d 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -81,6 +81,28 @@
     }
 
     /**
+     * Internal constants for the TTS functionality
+     *
+     * {@hide}
+     */
+    public class Engine {
+        // default values for a TTS engine when settings are not found in the provider
+        public static final int FALLBACK_TTS_DEFAULT_RATE = 100; // 1x
+        public static final int FALLBACK_TTS_DEFAULT_PITCH = 100;// 1x
+        public static final int FALLBACK_TTS_USE_DEFAULTS = 0; // false
+        public static final String FALLBACK_TTS_DEFAULT_LANG = "eng";
+        public static final String FALLBACK_TTS_DEFAULT_COUNTRY = "";
+        public static final String FALLBACK_TTS_DEFAULT_VARIANT = "";
+
+        // return codes for a TTS engine's check data activity
+        public static final int CHECK_VOICE_DATA_PASS = 1;
+        public static final int CHECK_VOICE_DATA_FAIL = 0;
+        public static final int CHECK_VOICE_DATA_BAD_DATA = -1;
+        public static final int CHECK_VOICE_DATA_MISSING_DATA = -2;
+        public static final int CHECK_VOICE_DATA_MISSING_DATA_NO_SDCARD = -3;
+    }
+
+    /**
      * Connection needed for the TTS.
      */
     private ServiceConnection mServiceConnection;
diff --git a/core/java/android/syncml/pim/vcard/ContactStruct.java b/core/java/android/syncml/pim/vcard/ContactStruct.java
index 5a29112..4b4c394 100644
--- a/core/java/android/syncml/pim/vcard/ContactStruct.java
+++ b/core/java/android/syncml/pim/vcard/ContactStruct.java
@@ -38,6 +38,7 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -181,6 +182,34 @@
         organizationList.add(organizationData);
     }
 
+    /**
+     * Set "position" value to the appropriate data. If there's more than one
+     * OrganizationData objects, the value is set to the last one. If there's no
+     * OrganizationData object, a new OrganizationData is created, whose company name is
+     * empty.  
+     * 
+     * TODO: incomplete logic. fix this:
+     * 
+     * e.g. This assumes ORG comes earlier, but TITLE may come earlier like this, though we do not
+     * know how to handle it in general cases...
+     * ----
+     * TITLE:Software Engineer
+     * ORG:Google
+     * ----
+     */
+    public void setPosition(String positionValue) {
+        if (organizationList == null) {
+            organizationList = new ArrayList<OrganizationData>();
+        }
+        int size = organizationList.size();
+        if (size == 0) {
+            addOrganization(Contacts.OrganizationColumns.TYPE_OTHER, "", null, false);
+            size = 1;
+        }
+        OrganizationData lastData = organizationList.get(size - 1);
+        lastData.positionName = positionValue;
+    }
+    
     public void addExtension(PropertyNode propertyNode) {
         if (propertyNode.propValue.length() == 0) {
             return;
@@ -427,8 +456,6 @@
             } else if (name.equals("ORG")) {
                 // vCard specification does not specify other types.
                 int type = Contacts.OrganizationColumns.TYPE_WORK;
-                String companyName = "";
-                String positionName = "";
                 boolean isPrimary = false;
                 
                 for (String typeString : propertyNode.paramMap_TYPE) {
@@ -442,29 +469,20 @@
                 }
 
                 List<String> list = propertyNode.propValue_vector; 
-                int size = list.size(); 
-                if (size > 1) {
-                    companyName = list.get(0);
-                    StringBuilder builder = new StringBuilder();
-                    for (int i = 1; i < size; i++) {
-                        builder.append(list.get(1));
-                        if (i != size - 1) {
-                            builder.append(", ");
-                        }
+                int size = list.size();
+                StringBuilder builder = new StringBuilder();
+                for (Iterator<String> iter = list.iterator(); iter.hasNext();) {
+                    builder.append(iter.next());
+                    if (iter.hasNext()) {
+                        builder.append(' ');
                     }
-                    positionName = builder.toString();
-                } else if (size == 1) {
-                    companyName = propertyNode.propValue;
-                    positionName = "";
                 }
-                contact.addOrganization(type, companyName, positionName, isPrimary);
+
+                contact.addOrganization(type, builder.toString(), "", isPrimary);
             } else if (name.equals("TITLE")) {
-                contact.title = propertyNode.propValue;
-                // XXX: What to do this? Isn't ORG enough?
-                contact.addExtension(propertyNode);
+                contact.setPosition(propertyNode.propValue);
             } else if (name.equals("ROLE")) {
-                // XXX: What to do this? Isn't ORG enough?
-                contact.addExtension(propertyNode);
+                contact.setPosition(propertyNode.propValue);
             } else if (name.equals("PHOTO")) {
                 // We prefer PHOTO to LOGO.
                 String valueType = propertyNode.paramMap.getAsString("VALUE");
diff --git a/core/java/android/test/InstrumentationTestCase.java b/core/java/android/test/InstrumentationTestCase.java
index 470ab0d..2145d7c 100644
--- a/core/java/android/test/InstrumentationTestCase.java
+++ b/core/java/android/test/InstrumentationTestCase.java
@@ -241,7 +241,13 @@
                 try {
                     final Field keyCodeField = KeyEvent.class.getField("KEYCODE_" + key);
                     final int keyCode = keyCodeField.getInt(null);
-                    instrumentation.sendKeyDownUpSync(keyCode);
+                    try {
+                        instrumentation.sendKeyDownUpSync(keyCode);
+                    } catch (SecurityException e) {
+                        // Ignore security exceptions that are now thrown
+                        // when trying to send to another app, to retain
+                        // compatibility with existing tests.
+                    }
                 } catch (NoSuchFieldException e) {
                     Log.w("ActivityTestCase", "Unknown keycode: KEYCODE_" + key);
                     break;
@@ -266,7 +272,13 @@
         final Instrumentation instrumentation = getInstrumentation();
 
         for (int i = 0; i < count; i++) {
-            instrumentation.sendKeyDownUpSync(keys[i]);
+            try {
+                instrumentation.sendKeyDownUpSync(keys[i]);
+            } catch (SecurityException e) {
+                // Ignore security exceptions that are now thrown
+                // when trying to send to another app, to retain
+                // compatibility with existing tests.
+            }
         }
 
         instrumentation.waitForIdleSync();
@@ -292,7 +304,13 @@
             final int keyCount = keys[i];
             final int keyCode = keys[i + 1];
             for (int j = 0; j < keyCount; j++) {
-                instrumentation.sendKeyDownUpSync(keyCode);
+                try {
+                    instrumentation.sendKeyDownUpSync(keyCode);
+                } catch (SecurityException e) {
+                    // Ignore security exceptions that are now thrown
+                    // when trying to send to another app, to retain
+                    // compatibility with existing tests.
+                }
             }
         }
 
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 245148d..a095913 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -37,8 +37,7 @@
      * The device's density.
      * @hide
      */
-    public static final int DEVICE_DENSITY = SystemProperties.getInt("ro.sf.lcd_density",
-            DEFAULT_DENSITY);
+    public static final int DEVICE_DENSITY = getDeviceDensity();
 
     /**
      * The absolute width of the display in pixels.
@@ -161,4 +160,13 @@
             ", height=" + heightPixels + ", scaledDensity=" + scaledDensity +
             ", xdpi=" + xdpi + ", ydpi=" + ydpi + "}";
     }
+
+    private static int getDeviceDensity() {
+        // qemu.sf.lcd_density can be used to override ro.sf.lcd_density
+        // when running in the emulator, allowing for dynamic configurations.
+        // The reason for this is that ro.sf.lcd_density is write-once and is
+        // set by the init process when it parses build.prop before anything else.
+        return SystemProperties.getInt("qemu.sf.lcd_density",
+                SystemProperties.getInt("ro.sf.lcd_density", DEFAULT_DENSITY));
+    }
 }
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
new file mode 100644
index 0000000..d90045f
--- /dev/null
+++ b/core/java/android/util/LongSparseArray.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2009 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.util;
+
+import com.android.internal.util.ArrayUtils;
+
+/**
+ * SparseArrays map longs to Objects.  Unlike a normal array of Objects,
+ * there can be gaps in the indices.  It is intended to be more efficient
+ * than using a HashMap to map Longs to Objects.
+ *
+ * @hide
+ */
+public class LongSparseArray<E> {
+    private static final Object DELETED = new Object();
+    private boolean mGarbage = false;
+
+    /**
+     * Creates a new SparseArray containing no mappings.
+     */
+    public LongSparseArray() {
+        this(10);
+    }
+
+    /**
+     * Creates a new SparseArray containing no mappings that will not
+     * require any additional memory allocation to store the specified
+     * number of mappings.
+     */
+    public LongSparseArray(int initialCapacity) {
+        initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
+
+        mKeys = new long[initialCapacity];
+        mValues = new Object[initialCapacity];
+        mSize = 0;
+    }
+
+    /**
+     * Gets the Object mapped from the specified key, or <code>null</code>
+     * if no such mapping has been made.
+     */
+    public E get(long key) {
+        return get(key, null);
+    }
+
+    /**
+     * Gets the Object mapped from the specified key, or the specified Object
+     * if no such mapping has been made.
+     */
+    public E get(long key, E valueIfKeyNotFound) {
+        int i = binarySearch(mKeys, 0, mSize, key);
+
+        if (i < 0 || mValues[i] == DELETED) {
+            return valueIfKeyNotFound;
+        } else {
+            return (E) mValues[i];
+        }
+    }
+
+    /**
+     * Removes the mapping from the specified key, if there was any.
+     */
+    public void delete(long key) {
+        int i = binarySearch(mKeys, 0, mSize, key);
+
+        if (i >= 0) {
+            if (mValues[i] != DELETED) {
+                mValues[i] = DELETED;
+                mGarbage = true;
+            }
+        }
+    }
+
+    /**
+     * Alias for {@link #delete(long)}.
+     */
+    public void remove(long key) {
+        delete(key);
+    }
+
+    private void gc() {
+        // Log.e("SparseArray", "gc start with " + mSize);
+
+        int n = mSize;
+        int o = 0;
+        long[] keys = mKeys;
+        Object[] values = mValues;
+
+        for (int i = 0; i < n; i++) {
+            Object val = values[i];
+
+            if (val != DELETED) {
+                if (i != o) {
+                    keys[o] = keys[i];
+                    values[o] = val;
+                }
+
+                o++;
+            }
+        }
+
+        mGarbage = false;
+        mSize = o;
+
+        // Log.e("SparseArray", "gc end with " + mSize);
+    }
+
+    /**
+     * Adds a mapping from the specified key to the specified value,
+     * replacing the previous mapping from the specified key if there
+     * was one.
+     */
+    public void put(long key, E value) {
+        int i = binarySearch(mKeys, 0, mSize, key);
+
+        if (i >= 0) {
+            mValues[i] = value;
+        } else {
+            i = ~i;
+
+            if (i < mSize && mValues[i] == DELETED) {
+                mKeys[i] = key;
+                mValues[i] = value;
+                return;
+            }
+
+            if (mGarbage && mSize >= mKeys.length) {
+                gc();
+
+                // Search again because indices may have changed.
+                i = ~binarySearch(mKeys, 0, mSize, key);
+            }
+
+            if (mSize >= mKeys.length) {
+                int n = ArrayUtils.idealIntArraySize(mSize + 1);
+
+                long[] nkeys = new long[n];
+                Object[] nvalues = new Object[n];
+
+                // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+                mKeys = nkeys;
+                mValues = nvalues;
+            }
+
+            if (mSize - i != 0) {
+                // Log.e("SparseArray", "move " + (mSize - i));
+                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+            }
+
+            mKeys[i] = key;
+            mValues[i] = value;
+            mSize++;
+        }
+    }
+
+    /**
+     * Returns the number of key-value mappings that this SparseArray
+     * currently stores.
+     */
+    public int size() {
+        if (mGarbage) {
+            gc();
+        }
+
+        return mSize;
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, returns
+     * the key from the <code>index</code>th key-value mapping that this
+     * SparseArray stores.
+     */
+    public long keyAt(int index) {
+        if (mGarbage) {
+            gc();
+        }
+
+        return mKeys[index];
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, returns
+     * the value from the <code>index</code>th key-value mapping that this
+     * SparseArray stores.
+     */
+    public E valueAt(int index) {
+        if (mGarbage) {
+            gc();
+        }
+
+        return (E) mValues[index];
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, sets a new
+     * value for the <code>index</code>th key-value mapping that this
+     * SparseArray stores.
+     */
+    public void setValueAt(int index, E value) {
+        if (mGarbage) {
+            gc();
+        }
+
+        mValues[index] = value;
+    }
+
+    /**
+     * Returns the index for which {@link #keyAt} would return the
+     * specified key, or a negative number if the specified
+     * key is not mapped.
+     */
+    public int indexOfKey(long key) {
+        if (mGarbage) {
+            gc();
+        }
+
+        return binarySearch(mKeys, 0, mSize, key);
+    }
+
+    /**
+     * Returns an index for which {@link #valueAt} would return the
+     * specified key, or a negative number if no keys map to the
+     * specified value.
+     * Beware that this is a linear search, unlike lookups by key,
+     * and that multiple keys can map to the same value and this will
+     * find only one of them.
+     */
+    public int indexOfValue(E value) {
+        if (mGarbage) {
+            gc();
+        }
+
+        for (int i = 0; i < mSize; i++)
+            if (mValues[i] == value)
+                return i;
+
+        return -1;
+    }
+
+    /**
+     * Removes all key-value mappings from this SparseArray.
+     */
+    public void clear() {
+        int n = mSize;
+        Object[] values = mValues;
+
+        for (int i = 0; i < n; i++) {
+            values[i] = null;
+        }
+
+        mSize = 0;
+        mGarbage = false;
+    }
+
+    /**
+     * Puts a key/value pair into the array, optimizing for the case where
+     * the key is greater than all existing keys in the array.
+     */
+    public void append(long key, E value) {
+        if (mSize != 0 && key <= mKeys[mSize - 1]) {
+            put(key, value);
+            return;
+        }
+
+        if (mGarbage && mSize >= mKeys.length) {
+            gc();
+        }
+
+        int pos = mSize;
+        if (pos >= mKeys.length) {
+            int n = ArrayUtils.idealIntArraySize(pos + 1);
+
+            long[] nkeys = new long[n];
+            Object[] nvalues = new Object[n];
+
+            // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+            System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+            System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+            mKeys = nkeys;
+            mValues = nvalues;
+        }
+
+        mKeys[pos] = key;
+        mValues[pos] = value;
+        mSize = pos + 1;
+    }
+
+    private static int binarySearch(long[] a, int start, int len, long key) {
+        int high = start + len, low = start - 1, guess;
+
+        while (high - low > 1) {
+            guess = (high + low) / 2;
+
+            if (a[guess] < key)
+                low = guess;
+            else
+                high = guess;
+        }
+
+        if (high == start + len)
+            return ~(start + len);
+        else if (a[high] == key)
+            return high;
+        else
+            return ~high;
+    }
+
+    private void checkIntegrity() {
+        for (int i = 1; i < mSize; i++) {
+            if (mKeys[i] <= mKeys[i - 1]) {
+                for (int j = 0; j < mSize; j++) {
+                    Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
+                }
+
+                throw new RuntimeException();
+            }
+        }
+    }
+
+    private long[] mKeys;
+    private Object[] mValues;
+    private int mSize;
+}
\ No newline at end of file
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e1c4687..e295d15 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -18,7 +18,6 @@
 
 import android.content.pm.ActivityInfo;
 import android.graphics.PixelFormat;
-import android.graphics.Rect;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -805,6 +804,7 @@
             screenOrientation = in.readInt();
         }
     
+        @SuppressWarnings({"PointlessBitwiseExpression"})
         public static final int LAYOUT_CHANGED = 1<<0;
         public static final int TYPE_CHANGED = 1<<1;
         public static final int FLAGS_CHANGED = 1<<2;
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 11de3e2..9a0f467 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -297,6 +297,10 @@
             b = tmp;
         }
 
+        if (a <= 0) {
+            return "";
+        }
+        
         if (length > a) {
             length = a;
         }
@@ -488,12 +492,12 @@
         } else {
             a = Selection.getSelectionStart(content);
             b = Selection.getSelectionEnd(content);
-            if (a >=0 && b>= 0 && a != b) {
-                if (b < a) {
-                    int tmp = a;
-                    a = b;
-                    b = tmp;
-                }
+            if (a < 0) a = 0;
+            if (b < 0) b = 0;
+            if (b < a) {
+                int tmp = a;
+                a = b;
+                b = tmp;
             }
         }
 
diff --git a/core/java/android/webkit/ByteArrayBuilder.java b/core/java/android/webkit/ByteArrayBuilder.java
index 806b458..145411c 100644
--- a/core/java/android/webkit/ByteArrayBuilder.java
+++ b/core/java/android/webkit/ByteArrayBuilder.java
@@ -17,6 +17,7 @@
 package android.webkit;
 
 import java.util.LinkedList;
+import java.util.ListIterator;
 
 /** Utility class optimized for accumulating bytes, and then spitting
     them back out.  It does not optimize for returning the result in a
@@ -94,6 +95,20 @@
         return mChunks.isEmpty();
     }
 
+    public int size() {
+        return mChunks.size();
+    }
+
+    public int getByteSize() {
+        int total = 0;
+        ListIterator<Chunk> it = mChunks.listIterator(0);
+        while (it.hasNext()) {
+            Chunk c = it.next();
+            total += c.mLength;
+        }
+        return total;
+    }
+
     public synchronized void clear() {
         Chunk c = getFirstChunk();
         while (c != null) {
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index 507fce3..7c071be 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -18,6 +18,7 @@
 
 import android.os.Handler;
 import android.os.Message;
+import android.security.Keystore;
 import android.util.Log;
 
 final class JWebCoreJavaBridge extends Handler {
@@ -135,10 +136,9 @@
     /**
      * Store a cookie string associated with a url.
      * @param url The url to be used as a key for the cookie.
-     * @param docUrl The policy base url used by WebCore.
      * @param value The cookie string to be stored.
      */
-    private void setCookies(String url, String docUrl, String value) {
+    private void setCookies(String url, String value) {
         if (value.contains("\r") || value.contains("\n")) {
             // for security reason, filter out '\r' and '\n' from the cookie
             int size = value.length();
@@ -223,18 +223,12 @@
     }
 
     private String[] getKeyStrengthList() {
-        // FIXME: fake the list for now
-        String[] list = new String[2];
-        list[0] = "1024";
-        list[1] = "512";
-        return list;
+        return Keystore.getInstance().getSupportedKeyStrenghs();
     }
 
     private String getSignedPublicKey(int index, String challenge, String url) {
-        // FIXME: do nothing for now
-        Log.w(LOGTAG, "getSignedPublicKey for " + index + " and challenge="
-                + challenge + " and url=" + url);
-        return "";
+        // generateKeyPair expects organizations which we don't have. Ignore url.
+        return Keystore.getInstance().generateKeyPair(index, challenge, null);
     }
 
     private native void nativeConstructor();
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 1ebdb79..08854f7 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -25,16 +25,16 @@
 import android.net.http.RequestHandle;
 import android.net.http.SslCertificate;
 import android.net.http.SslError;
-import android.net.http.SslCertificate;
 
 import android.os.Handler;
 import android.os.Message;
+import android.security.Keystore;
 import android.util.Log;
 import android.webkit.CacheManager.CacheResult;
+import android.widget.Toast;
 
 import com.android.internal.R;
 
-import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -70,6 +70,8 @@
     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 int sNativeLoaderCount;
 
     private final ByteArrayBuilder mDataBuilder = new ByteArrayBuilder(8192);
@@ -919,6 +921,12 @@
 
     // This commits the headers without checking the response status code.
     private void commitHeaders() {
+        if (mIsMainPageLoader && CERT_MIMETYPE.equals(mMimeType)) {
+            // In the case of downloading certificate, we will save it to the
+            // Keystore in commitLoad. Do not call webcore.
+            return;
+        }
+
         // Commit the headers to WebCore
         int nativeResponse = createNativeResponse();
         // The native code deletes the native response object.
@@ -959,6 +967,30 @@
     private void commitLoad() {
         if (mCancelled) return;
 
+        if (mIsMainPageLoader && CERT_MIMETYPE.equals(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
+            byte[] cert = new byte[mDataBuilder.getByteSize()];
+            int position = 0;
+            ByteArrayBuilder.Chunk c;
+            while (true) {
+                c = mDataBuilder.getFirstChunk();
+                if (c == null) break;
+
+                if (c.mLength != 0) {
+                    System.arraycopy(c.mArray, 0, cert, position, c.mLength);
+                    position += c.mLength;
+                }
+                mDataBuilder.releaseChunk(c);
+            }
+            Keystore.getInstance().addCertificate(cert);
+            Toast.makeText(mContext, R.string.certificateSaved,
+                    Toast.LENGTH_SHORT).show();
+            mBrowserFrame.stopLoading();
+            return;
+        }
+
         // Give the data to WebKit now
         PerfChecker checker = new PerfChecker();
         ByteArrayBuilder.Chunk c;
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index f27360d..0488691 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -200,8 +200,13 @@
      */
     public void setQuotaForOrigin(String origin, long quota) {
         if (origin != null) {
-            postMessage(Message.obtain(null, SET_QUOTA_ORIGIN,
-                new Origin(origin, quota)));
+            if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+                nativeSetQuotaForOrigin(origin, quota);
+                syncValues();
+            } else {
+                postMessage(Message.obtain(null, SET_QUOTA_ORIGIN,
+                    new Origin(origin, quota)));
+            }
         }
     }
 
@@ -211,8 +216,13 @@
      */
     public void deleteOrigin(String origin) {
         if (origin != null) {
-            postMessage(Message.obtain(null, DELETE_ORIGIN,
-                new Origin(origin)));
+            if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+                nativeDeleteOrigin(origin);
+                syncValues();
+            } else {
+                postMessage(Message.obtain(null, DELETE_ORIGIN,
+                    new Origin(origin)));
+            }
         }
     }
 
@@ -221,7 +231,12 @@
      * Delete all databases
      */
     public void deleteAllDatabases() {
-        postMessage(Message.obtain(null, DELETE_ALL));
+        if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+            nativeDeleteAllDatabases();
+            syncValues();
+        } else {
+            postMessage(Message.obtain(null, DELETE_ALL));
+        }
     }
 
     /**
@@ -250,7 +265,11 @@
      * Post a Sync request
      */
     public void update() {
-        postMessage(Message.obtain(null, UPDATE));
+        if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+            syncValues();
+        } else {
+            postMessage(Message.obtain(null, UPDATE));
+        }
     }
 
     /**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 9c19ced..186e1d1 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -489,22 +489,27 @@
     // width which view is considered to be fully zoomed out
     static final int ZOOM_OUT_WIDTH = 1008;
 
-    private static final float DEFAULT_MAX_ZOOM_SCALE = 4.0f;
-    private static final float DEFAULT_MIN_ZOOM_SCALE = 0.25f;
+    // default scale limit. Depending on the display density
+    private static float DEFAULT_MAX_ZOOM_SCALE;
+    private static float DEFAULT_MIN_ZOOM_SCALE;
     // scale limit, which can be set through viewport meta tag in the web page
-    private float mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
-    private float mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
+    private float mMaxZoomScale;
+    private float mMinZoomScale;
     private boolean mMinZoomScaleFixed = false;
 
     // initial scale in percent. 0 means using default.
     private int mInitialScale = 0;
 
+    // default scale. Depending on the display density.
+    static int DEFAULT_SCALE_PERCENT;
+    private float DEFAULT_SCALE;
+
     // set to true temporarily while the zoom control is being dragged
     private boolean mPreviewZoomOnly = false;
 
     // computed scale and inverse, from mZoomWidth.
-    private float mActualScale = 1;
-    private float mInvActualScale = 1;
+    private float mActualScale;
+    private float mInvActualScale;
     // if this is non-zero, it is used on drawing rather than mActualScale
     private float mZoomScale;
     private float mInvInitialZoomScale;
@@ -734,10 +739,19 @@
         final int slop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
         mTouchSlopSquare = slop * slop;
         mMinLockSnapReverseDistance = slop;
+        final float density = getContext().getResources().getDisplayMetrics().density;
         // use one line height, 16 based on our current default font, for how
         // far we allow a touch be away from the edge of a link
-        mNavSlop = (int) (16 * getContext().getResources()
-                .getDisplayMetrics().density);
+        mNavSlop = (int) (16 * density);
+        // density adjusted scale factors
+        DEFAULT_SCALE_PERCENT = (int) (100 * density);
+        DEFAULT_SCALE = density;
+        mActualScale = density;
+        mInvActualScale = 1 / density;
+        DEFAULT_MAX_ZOOM_SCALE = 4.0f * density;
+        DEFAULT_MIN_ZOOM_SCALE = 0.25f * density;
+        mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
+        mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
     }
 
     /* package */ boolean onSavePassword(String schemePlusHost, String username,
@@ -1745,9 +1759,6 @@
     private Rect sendOurVisibleRect() {
         Rect rect = new Rect();
         calcOurContentVisibleRect(rect);
-        if (mFindIsUp) {
-            rect.bottom -= viewToContent(FIND_HEIGHT);
-        }
         // Rect.equals() checks for null input.
         if (!rect.equals(mLastVisibleRectSent)) {
             Point pos = new Point(rect.left, rect.top);
@@ -1758,6 +1769,11 @@
         Rect globalRect = new Rect();
         if (getGlobalVisibleRect(globalRect)
                 && !globalRect.equals(mLastGlobalRect)) {
+            if (DebugFlags.WEB_VIEW) {
+                Log.v(LOGTAG, "sendOurVisibleRect=(" + globalRect.left + ","
+                        + globalRect.top + ",r=" + globalRect.right + ",b="
+                        + globalRect.bottom);
+            }
             // TODO: the global offset is only used by windowRect()
             // in ChromeClientAndroid ; other clients such as touch
             // and mouse events could return view + screen relative points.
@@ -1772,6 +1788,9 @@
         Point p = new Point();
         getGlobalVisibleRect(r, p);
         r.offset(-p.x, -p.y);
+        if (mFindIsUp) {
+            r.bottom -= FIND_HEIGHT;
+        }
     }
 
     // Sets r to be our visible rectangle in content coordinates
@@ -2992,7 +3011,8 @@
             mTextGeneration = 0;
         }
         mWebTextView.setTextSize(contentToView(nativeFocusCandidateTextSize()));
-        Rect visibleRect = sendOurVisibleRect();
+        Rect visibleRect = new Rect();
+        calcOurContentVisibleRect(visibleRect);
         // Note that sendOurVisibleRect calls viewToContent, so the coordinates
         // should be in content coordinates.
         Rect bounds = nativeFocusCandidateNodeBounds();
@@ -4217,9 +4237,9 @@
     private boolean zoomWithPreview(float scale) {
         float oldScale = mActualScale;
 
-        // snap to 100% if it is close
-        if (scale > 0.95f && scale < 1.05f) {
-            scale = 1.0f;
+        // snap to DEFAULT_SCALE if it is close
+        if (scale > (DEFAULT_SCALE - 0.05) && scale < (DEFAULT_SCALE + 0.05)) {
+            scale = DEFAULT_SCALE;
         }
 
         setNewZoomScale(scale, false);
@@ -4748,8 +4768,8 @@
                     }
                     int initialScale = msg.arg1;
                     int viewportWidth = msg.arg2;
-                    // by default starting a new page with 100% zoom scale.
-                    float scale = 1.0f;
+                    // start a new page with DEFAULT_SCALE zoom scale.
+                    float scale = DEFAULT_SCALE;
                     if (mInitialScale > 0) {
                         scale = mInitialScale / 100.0f;
                     } else  {
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 5393624..4ad9a1a 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -94,7 +94,7 @@
 
     private boolean mViewportUserScalable = true;
 
-    private int mRestoredScale = 100;
+    private int mRestoredScale = WebView.DEFAULT_SCALE_PERCENT;
     private int mRestoredX = 0;
     private int mRestoredY = 0;
 
@@ -1621,16 +1621,16 @@
         // infer the values if they are not defined.
         if (mViewportWidth == 0) {
             if (mViewportInitialScale == 0) {
-                mViewportInitialScale = 100;
+                mViewportInitialScale = WebView.DEFAULT_SCALE_PERCENT;
             }
             if (mViewportMinimumScale == 0) {
-                mViewportMinimumScale = 100;
+                mViewportMinimumScale = WebView.DEFAULT_SCALE_PERCENT;
             }
         }
         if (mViewportUserScalable == false) {
-            mViewportInitialScale = 100;
-            mViewportMinimumScale = 100;
-            mViewportMaximumScale = 100;
+            mViewportInitialScale = WebView.DEFAULT_SCALE_PERCENT;
+            mViewportMinimumScale = WebView.DEFAULT_SCALE_PERCENT;
+            mViewportMaximumScale = WebView.DEFAULT_SCALE_PERCENT;
         }
         if (mViewportMinimumScale > mViewportInitialScale) {
             if (mViewportInitialScale == 0) {
@@ -1646,7 +1646,8 @@
                 mViewportInitialScale = mViewportMaximumScale;
             }
         }
-        if (mViewportWidth < 0 && mViewportInitialScale == 100) {
+        if (mViewportWidth < 0
+                && mViewportInitialScale == WebView.DEFAULT_SCALE_PERCENT) {
             mViewportWidth = 0;
         }
 
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 1c66803..746d5c3 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -571,7 +571,7 @@
         if (isPopupShowing()) {
             // special case for the back key, we do not even try to send it
             // to the drop down list but instead, consume it immediately
-            if (keyCode == KeyEvent.KEYCODE_BACK) {
+            if (keyCode == KeyEvent.KEYCODE_BACK && !mDropDownAlwaysVisible) {
                 dismissDropDown();
                 return true;
             }
@@ -741,7 +741,7 @@
         } else {
             // drop down is automatically dismissed when enough characters
             // are deleted from the text view
-            dismissDropDown();
+            if (!mDropDownAlwaysVisible) dismissDropDown();
             if (mFilter != null) {
                 mFilter.filter(null);
             }
@@ -882,7 +882,7 @@
             }
         }
 
-        if (mDropDownDismissedOnCompletion) {
+        if (mDropDownDismissedOnCompletion && !mDropDownAlwaysVisible) {
             dismissDropDown();
         }
     }
@@ -963,7 +963,7 @@
             if (hasFocus() && hasWindowFocus()) {
                 showDropDown();
             }
-        } else {
+        } else if (!mDropDownAlwaysVisible) {
             dismissDropDown();
         }
     }
@@ -972,7 +972,7 @@
     public void onWindowFocusChanged(boolean hasWindowFocus) {
         super.onWindowFocusChanged(hasWindowFocus);
         performValidation();
-        if (!hasWindowFocus) {
+        if (!hasWindowFocus && !mDropDownAlwaysVisible) {
             dismissDropDown();
         }
     }
@@ -981,7 +981,7 @@
     protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
         super.onFocusChanged(focused, direction, previouslyFocusedRect);
         performValidation();
-        if (!focused) {
+        if (!focused && !mDropDownAlwaysVisible) {
             dismissDropDown();
         }
     }
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 68764a5..b188c31 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -823,6 +823,7 @@
         p.flags = computeFlags(p.flags);
         p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
         p.token = token;
+        p.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
         p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));
 
         return p;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5c75af2c..9479f9e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -416,6 +416,7 @@
         boolean singleLine = false;
         int maxlength = -1;
         CharSequence text = "";
+        CharSequence hint = null;
         int shadowcolor = 0;
         float dx = 0, dy = 0, r = 0;
         boolean password = false;
@@ -543,7 +544,7 @@
                 break;
 
             case com.android.internal.R.styleable.TextView_hint:
-                setHint(a.getText(attr));
+                hint = a.getText(attr);
                 break;
 
             case com.android.internal.R.styleable.TextView_text:
@@ -873,6 +874,7 @@
         }
 
         setText(text, bufferType);
+        if (hint != null) setHint(hint);
 
         /*
          * Views are not normally focusable unless specified to be.
@@ -2817,8 +2819,9 @@
             checkForRelayout();
         }
 
-        if (mText.length() == 0)
+        if (mText.length() == 0) {
             invalidate();
+        }
     }
 
     /**
@@ -4802,10 +4805,12 @@
                 alignment = Layout.Alignment.ALIGN_NORMAL;
         }
 
+        boolean shouldEllipsize = mEllipsize != null && mInput == null;
+
         if (mText instanceof Spannable) {
             mLayout = new DynamicLayout(mText, mTransformed, mTextPaint, w,
                     alignment, mSpacingMult,
-                    mSpacingAdd, mIncludePad, mEllipsize,
+                    mSpacingAdd, mIncludePad, mInput == null ? mEllipsize : null,
                     ellipsisWidth);
         } else {
             if (boring == UNKNOWN_BORING) {
@@ -4832,7 +4837,7 @@
                     // Log.e("aaa", "Boring: " + mTransformed);
 
                     mSavedLayout = (BoringLayout) mLayout;
-                } else if (mEllipsize != null && boring.width <= w) {
+                } else if (shouldEllipsize && boring.width <= w) {
                     if (mSavedLayout != null) {
                         mLayout = mSavedLayout.
                                 replaceOrMake(mTransformed, mTextPaint,
@@ -4845,7 +4850,7 @@
                                 boring, mIncludePad, mEllipsize,
                                 ellipsisWidth);
                     }
-                } else if (mEllipsize != null) {
+                } else if (shouldEllipsize) {
                     mLayout = new StaticLayout(mTransformed,
                                 0, mTransformed.length(),
                                 mTextPaint, w, alignment, mSpacingMult,
@@ -4857,7 +4862,7 @@
                             mIncludePad);
                     // Log.e("aaa", "Boring but wide: " + mTransformed);
                 }
-            } else if (mEllipsize != null) {
+            } else if (shouldEllipsize) {
                 mLayout = new StaticLayout(mTransformed,
                             0, mTransformed.length(),
                             mTextPaint, w, alignment, mSpacingMult,
@@ -4870,9 +4875,12 @@
             }
         }
 
+        shouldEllipsize = mEllipsize != null;
         mHintLayout = null;
 
         if (mHint != null) {
+            if (shouldEllipsize) hintWidth = w;
+
             if (hintBoring == UNKNOWN_BORING) {
                 hintBoring = BoringLayout.isBoring(mHint, mTextPaint,
                                                    mHintBoring);
@@ -4882,24 +4890,50 @@
             }
 
             if (hintBoring != null) {
-                if (hintBoring.width <= hintWidth) {
+                if (hintBoring.width <= hintWidth &&
+                    (!shouldEllipsize || hintBoring.width <= ellipsisWidth)) {
                     if (mSavedHintLayout != null) {
                         mHintLayout = mSavedHintLayout.
                                 replaceOrMake(mHint, mTextPaint,
-                                hintWidth, alignment, mSpacingMult,
-                                mSpacingAdd, hintBoring, mIncludePad);
+                                hintWidth, alignment, mSpacingMult, mSpacingAdd,
+                                hintBoring, mIncludePad);
                     } else {
                         mHintLayout = BoringLayout.make(mHint, mTextPaint,
-                                hintWidth, alignment, mSpacingMult,
-                                mSpacingAdd, hintBoring, mIncludePad);
+                                hintWidth, alignment, mSpacingMult, mSpacingAdd,
+                                hintBoring, mIncludePad);
                     }
 
                     mSavedHintLayout = (BoringLayout) mHintLayout;
+                } else if (shouldEllipsize && hintBoring.width <= hintWidth) {
+                    if (mSavedHintLayout != null) {
+                        mHintLayout = mSavedHintLayout.
+                                replaceOrMake(mHint, mTextPaint,
+                                hintWidth, alignment, mSpacingMult, mSpacingAdd,
+                                hintBoring, mIncludePad, mEllipsize,
+                                ellipsisWidth);
+                    } else {
+                        mHintLayout = BoringLayout.make(mHint, mTextPaint,
+                                hintWidth, alignment, mSpacingMult, mSpacingAdd,
+                                hintBoring, mIncludePad, mEllipsize,
+                                ellipsisWidth);
+                    }
+                } else if (shouldEllipsize) {
+                    mHintLayout = new StaticLayout(mHint,
+                                0, mHint.length(),
+                                mTextPaint, hintWidth, alignment, mSpacingMult,
+                                mSpacingAdd, mIncludePad, mEllipsize,
+                                ellipsisWidth);
                 } else {
                     mHintLayout = new StaticLayout(mHint, mTextPaint,
                             hintWidth, alignment, mSpacingMult, mSpacingAdd,
                             mIncludePad);
                 }
+            } else if (shouldEllipsize) {
+                mHintLayout = new StaticLayout(mHint,
+                            0, mHint.length(),
+                            mTextPaint, hintWidth, alignment, mSpacingMult,
+                            mSpacingAdd, mIncludePad, mEllipsize,
+                            ellipsisWidth);
             } else {
                 mHintLayout = new StaticLayout(mHint, mTextPaint,
                         hintWidth, alignment, mSpacingMult, mSpacingAdd,
@@ -4983,8 +5017,7 @@
         }
     }
 
-    private static final BoringLayout.Metrics UNKNOWN_BORING =
-                                                new BoringLayout.Metrics();
+    private static final BoringLayout.Metrics UNKNOWN_BORING = new BoringLayout.Metrics();
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
@@ -5011,8 +5044,7 @@
             }
 
             if (des < 0) {
-                boring = BoringLayout.isBoring(mTransformed, mTextPaint,
-                                               mBoring);
+                boring = BoringLayout.isBoring(mTransformed, mTextPaint, mBoring);
                 if (boring != null) {
                     mBoring = boring;
                 }
@@ -5022,8 +5054,7 @@
 
             if (boring == null || boring == UNKNOWN_BORING) {
                 if (des < 0) {
-                    des = (int) FloatMath.ceil(Layout.
-                                    getDesiredWidth(mTransformed, mTextPaint));
+                    des = (int) FloatMath.ceil(Layout.getDesiredWidth(mTransformed, mTextPaint));
                 }
 
                 width = des;
@@ -5041,13 +5072,12 @@
                 int hintDes = -1;
                 int hintWidth;
 
-                if (mHintLayout != null) {
+                if (mHintLayout != null && mEllipsize == null) {
                     hintDes = desired(mHintLayout);
                 }
 
                 if (hintDes < 0) {
-                    hintBoring = BoringLayout.isBoring(mHint, mTextPaint,
-                                                       mHintBoring);
+                    hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mHintBoring);
                     if (hintBoring != null) {
                         mHintBoring = hintBoring;
                     }
@@ -5055,8 +5085,8 @@
 
                 if (hintBoring == null || hintBoring == UNKNOWN_BORING) {
                     if (hintDes < 0) {
-                        hintDes = (int) FloatMath.ceil(Layout.
-                                        getDesiredWidth(mHint, mTextPaint));
+                        hintDes = (int) FloatMath.ceil(
+                                Layout.getDesiredWidth(mHint, mTextPaint));
                     }
 
                     hintWidth = hintDes;
@@ -5102,20 +5132,18 @@
 
         if (mLayout == null) {
             makeNewLayout(want, hintWant, boring, hintBoring,
-                          width - getCompoundPaddingLeft() - getCompoundPaddingRight(),
-                          false);
+                          width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false);
         } else if ((mLayout.getWidth() != want) || (hintWidth != hintWant) ||
                    (mLayout.getEllipsizedWidth() !=
                         width - getCompoundPaddingLeft() - getCompoundPaddingRight())) {
             if (mHint == null && mEllipsize == null &&
                     want > mLayout.getWidth() &&
                     (mLayout instanceof BoringLayout ||
-                        (fromexisting && des >= 0 && des <= want))) {
+                            (fromexisting && des >= 0 && des <= want))) {
                 mLayout.increaseWidthTo(want);
             } else {
                 makeNewLayout(want, hintWant, boring, hintBoring,
-                              width - getCompoundPaddingLeft() - getCompoundPaddingRight(),
-                              false);
+                              width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false);
             }
         } else {
             // Width has not changed.
@@ -5136,11 +5164,9 @@
             }
         }
 
-        int unpaddedHeight = height - getCompoundPaddingTop() -
-                                getCompoundPaddingBottom();
+        int unpaddedHeight = height - getCompoundPaddingTop() - getCompoundPaddingBottom();
         if (mMaxMode == LINES && mLayout.getLineCount() > mMaximum) {
-            unpaddedHeight = Math.min(unpaddedHeight,
-                                      mLayout.getLineTop(mMaximum));
+            unpaddedHeight = Math.min(unpaddedHeight, mLayout.getLineTop(mMaximum));
         }
 
         /*
@@ -5159,8 +5185,9 @@
     }
 
     private int getDesiredHeight() {
-        return Math.max(getDesiredHeight(mLayout, true),
-                        getDesiredHeight(mHintLayout, false));
+        return Math.max(
+                getDesiredHeight(mLayout, true),
+                getDesiredHeight(mHintLayout, mEllipsize != null));
     }
 
     private int getDesiredHeight(Layout layout, boolean cap) {
@@ -5803,6 +5830,9 @@
     }
 
     private void startMarquee() {
+        // Do not ellipsize EditText
+        if (mInput != null) return;
+
         if (compressText(getWidth() - getCompoundPaddingLeft() - getCompoundPaddingRight())) {
             return;
         }
@@ -6439,6 +6469,13 @@
         
         protected void onReceiveResult(int resultCode, Bundle resultData) {
             if (resultCode != InputMethodManager.RESULT_SHOWN) {
+                final int len = mText.length();
+                if (mNewStart > len) {
+                    mNewStart = len;
+                }
+                if (mNewEnd > len) {
+                    mNewEnd = len;
+                }
                 Selection.setSelection((Spannable)mText, mNewStart, mNewEnd);
             }
         }
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 5caa015..3dd71f3 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -80,28 +80,35 @@
             byte[] buf = new byte[bufSize];
             while (changeSet.readNextHeader()) {
                 String key = changeSet.getKey();
+                String base64Key = new String(Base64.encode(key.getBytes()));
+                File entityFile = new File(packageDir, base64Key);
+
                 int dataSize = changeSet.getDataSize();
 
-                String base64Key = new String(Base64.encode(key.getBytes()));
                 if (DEBUG) Log.v(TAG, "Got change set key=" + key + " size=" + dataSize
                         + " key64=" + base64Key);
-                if (dataSize > bufSize) {
-                    bufSize = dataSize;
-                    buf = new byte[bufSize];
-                }
-                changeSet.readEntityData(buf, 0, dataSize);
-                if (DEBUG) Log.v(TAG, "  + data size " + dataSize);
 
-                File entityFile = new File(packageDir, base64Key);
-                FileOutputStream entity = new FileOutputStream(entityFile);
-                try {
-                    entity.write(buf, 0, dataSize);
-                } catch (IOException e) {
-                    Log.e(TAG, "Unable to update key file "
-                            + entityFile.getAbsolutePath());
-                    err = -1;
-                } finally {
-                    entity.close();
+                if (dataSize >= 0) {
+                    FileOutputStream entity = new FileOutputStream(entityFile);
+
+                    if (dataSize > bufSize) {
+                        bufSize = dataSize;
+                        buf = new byte[bufSize];
+                    }
+                    changeSet.readEntityData(buf, 0, dataSize);
+                    if (DEBUG) Log.v(TAG, "  data size " + dataSize);
+
+                    try {
+                        entity.write(buf, 0, dataSize);
+                    } catch (IOException e) {
+                        Log.e(TAG, "Unable to update key file "
+                                + entityFile.getAbsolutePath());
+                        err = -1;
+                    } finally {
+                        entity.close();
+                    }
+                } else {
+                    entityFile.delete();
                 }
             }
         } catch (IOException e) {
@@ -163,17 +170,13 @@
         // The restore set is the concatenation of the individual record blobs,
         // each of which is a file in the package's directory
         File[] blobs = packageDir.listFiles();
+        if (DEBUG) Log.v(TAG, "   found " + blobs.length + " key files");
         int err = 0;
         if (blobs != null && blobs.length > 0) {
             BackupDataOutput out = new BackupDataOutput(outFd.getFileDescriptor());
             try {
                 for (File f : blobs) {
-                    FileInputStream in = new FileInputStream(f);
-                    int size = (int) f.length();
-                    byte[] buf = new byte[size];
-                    in.read(buf);
-                    out.writeEntityHeader(f.getName(), size);
-                    out.writeEntityData(buf, size);
+                    copyToRestoreData(f, out);
                 }
             } catch (Exception e) {
                 Log.e(TAG, "Unable to read backup records");
@@ -182,4 +185,16 @@
         }
         return err;
     }
+
+    private void copyToRestoreData(File f, BackupDataOutput out) throws IOException {
+        FileInputStream in = new FileInputStream(f);
+        int size = (int) f.length();
+        byte[] buf = new byte[size];
+        in.read(buf);
+        String key = new String(Base64.decode(f.getName()));
+        if (DEBUG) Log.v(TAG, "   ... copy to stream: key=" + key
+                + " size=" + size);
+        out.writeEntityHeader(key, size);
+        out.writeEntityData(buf, size);
+    }
 }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index aca6670..0ecf678 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -11,6 +11,10 @@
 	LOCAL_CFLAGS += -DPACKED=""
 endif
 
+ifeq ($(WITH_JIT),true)
+	LOCAL_CFLAGS += -DWITH_JIT
+endif
+
 ifneq ($(USE_CUSTOM_RUNTIME_HEAP_MAX),)
   LOCAL_CFLAGS += -DCUSTOM_RUNTIME_HEAP_MAX=$(USE_CUSTOM_RUNTIME_HEAP_MAX)
 endif
@@ -117,7 +121,7 @@
 	com_android_internal_graphics_NativeUtils.cpp \
 	android_backup_BackupDataInput.cpp \
 	android_backup_BackupDataOutput.cpp \
-	android_backup_FileBackupHelper.cpp
+	android_backup_FileBackupHelperBase.cpp
 
 LOCAL_C_INCLUDES += \
 	$(JNI_H_INCLUDE) \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 4512fef..f8a4df0 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -155,7 +155,7 @@
 extern int register_android_location_GpsLocationProvider(JNIEnv* env);
 extern int register_android_backup_BackupDataInput(JNIEnv *env);
 extern int register_android_backup_BackupDataOutput(JNIEnv *env);
-extern int register_android_backup_FileBackupHelper(JNIEnv *env);
+extern int register_android_backup_FileBackupHelperBase(JNIEnv *env);
 
 static AndroidRuntime* gCurRuntime = NULL;
 
@@ -528,7 +528,14 @@
     bool checkJni = false;
     bool checkDexSum = false;
     bool logStdio = false;
-    enum { kEMDefault, kEMIntPortable, kEMIntFast } executionMode = kEMDefault;
+    enum {
+      kEMDefault,
+      kEMIntPortable,
+      kEMIntFast,
+#if defined(WITH_JIT)
+      kEMJitCompiler,
+#endif
+    } executionMode = kEMDefault;
 
 
     property_get("dalvik.vm.checkjni", propBuf, "");
@@ -547,6 +554,10 @@
         executionMode = kEMIntPortable;
     } else if (strcmp(propBuf, "int:fast") == 0) {
         executionMode = kEMIntFast;
+#if defined(WITH_JIT)
+    } else if (strcmp(propBuf, "int:jit") == 0) {
+        executionMode = kEMJitCompiler;
+#endif
     }
 
     property_get("dalvik.vm.stack-trace-file", stackTraceFileBuf, "");
@@ -683,12 +694,70 @@
         //opt.optionString = "-verbose:jni";
         //mOptions.add(opt);
     }
+
+#if defined(WITH_JIT)
+    /* Minimal profile threshold to trigger JIT compilation */
+    char jitThresholdBuf[sizeof("-Xthreshold:") + PROPERTY_VALUE_MAX];
+    property_get("dalvik.vm.jit.threshold", propBuf, "");
+    if (strlen(propBuf) > 0) {
+        strcpy(jitThresholdBuf, "-Xthreshold:");
+        strcat(jitThresholdBuf, propBuf);
+        opt.optionString = jitThresholdBuf;
+        mOptions.add(opt);
+    }
+
+    /* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */
+    char jitOpBuf[sizeof("-Xjitop:") + PROPERTY_VALUE_MAX];
+    property_get("dalvik.vm.jit.op", propBuf, "");
+    if (strlen(propBuf) > 0) {
+        strcpy(jitOpBuf, "-Xjitop:");
+        strcat(jitOpBuf, propBuf);
+        opt.optionString = jitOpBuf;
+        mOptions.add(opt);
+    }
+
+    /*
+     * Reverse the polarity of dalvik.vm.jit.op and force interpreter-only
+     * for non-selected opcodes.
+     */
+    property_get("dalvik.vm.jit.includeop", propBuf, "");
+    if (strlen(propBuf) > 0) {
+        opt.optionString = "-Xincludeselectedop";
+        mOptions.add(opt);
+    }
+
+    /* Force interpreter-only mode for selected methods */
+    char jitMethodBuf[sizeof("-Xjitmethod:") + PROPERTY_VALUE_MAX];
+    property_get("dalvik.vm.jit.method", propBuf, "");
+    if (strlen(propBuf) > 0) {
+        strcpy(jitMethodBuf, "-Xjitmethod:");
+        strcat(jitMethodBuf, propBuf);
+        opt.optionString = jitMethodBuf;
+        mOptions.add(opt);
+    }
+
+    /*
+     * Reverse the polarity of dalvik.vm.jit.method and force interpreter-only
+     * for non-selected methods.
+     */
+    property_get("dalvik.vm.jit.includemethod", propBuf, "");
+    if (strlen(propBuf) > 0) {
+        opt.optionString = "-Xincludeselectedmethod";
+        mOptions.add(opt);
+    }
+#endif
+
     if (executionMode == kEMIntPortable) {
         opt.optionString = "-Xint:portable";
         mOptions.add(opt);
     } else if (executionMode == kEMIntFast) {
         opt.optionString = "-Xint:fast";
         mOptions.add(opt);
+#if defined(WITH_JIT)
+    } else if (executionMode == kEMJitCompiler) {
+        opt.optionString = "-Xint:jit";
+        mOptions.add(opt);
+#endif
     }
 
     if (checkDexSum) {
@@ -1171,7 +1240,7 @@
     REG_JNI(register_android_location_GpsLocationProvider),
     REG_JNI(register_android_backup_BackupDataInput),
     REG_JNI(register_android_backup_BackupDataOutput),
-    REG_JNI(register_android_backup_FileBackupHelper),
+    REG_JNI(register_android_backup_FileBackupHelperBase),
 };
 
 /*
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 29d8d3c..957b825 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -28,7 +28,7 @@
 static void FromColor_D32(void* dst, const SkColor src[], int width,

                           int, int) {

     SkPMColor* d = (SkPMColor*)dst;

-    

+

     for (int i = 0; i < width; i++) {

         *d++ = SkPreMultiplyColor(*src++);

     }

@@ -37,7 +37,7 @@
 static void FromColor_D565(void* dst, const SkColor src[], int width,

                            int x, int y) {

     uint16_t* d = (uint16_t*)dst;

-    

+

     DITHER_565_SCAN(y);

     for (int stop = x + width; x < stop; x++) {

         SkColor c = *src++;

@@ -49,7 +49,7 @@
 static void FromColor_D4444(void* dst, const SkColor src[], int width,

                             int x, int y) {

     SkPMColor16* d = (SkPMColor16*)dst;

-    

+

     DITHER_4444_SCAN(y);

     for (int stop = x + width; x < stop; x++) {

         SkPMColor c = SkPreMultiplyColor(*src++);

@@ -80,14 +80,14 @@
     SkAutoLockPixels alp(dstBitmap);

     void* dst = dstBitmap.getPixels();

     FromColorProc proc = ChooseFromColorProc(dstBitmap.config());

-    

+

     if (NULL == dst || NULL == proc) {

         return false;

     }

-    

+

     const jint* array = env->GetIntArrayElements(srcColors, NULL);

     const SkColor* src = (const SkColor*)array + srcOffset;

-    

+

     // reset to to actual choice from caller

     dst = dstBitmap.getAddr(x, y);

     // now copy/convert each scanline

@@ -96,7 +96,7 @@
         src += srcStride;

         dst = (char*)dst + dstBitmap.rowBytes();

     }

-    

+

     env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),

                                  JNI_ABORT);

     return true;

@@ -212,7 +212,7 @@
         doThrowIAE(env, "width and height must be > 0");

         return NULL;

     }

-    

+

     if (NULL != jColors) {

         size_t n = env->GetArrayLength(jColors);

         if (n < SkAbs32(stride) * (size_t)height) {

@@ -222,7 +222,7 @@
     }

 

     SkBitmap bitmap;

-    

+

     bitmap.setConfig(config, width, height);

     if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL)) {

         return NULL;

@@ -232,7 +232,7 @@
         GraphicsJNI::SetPixels(env, jColors, offset, stride,

                                0, 0, width, height, bitmap);

     }

-    

+

     return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), isMutable,

                                      NULL);

 }

@@ -245,7 +245,7 @@
     if (!src->copyTo(&result, dstConfig, &allocator)) {

         return NULL;

     }

-    

+

     return GraphicsJNI::createBitmap(env, new SkBitmap(result), isMutable,

                                      NULL);

 }

@@ -324,15 +324,15 @@
         SkDebugf("-------- unparcel parcel is NULL\n");

         return NULL;

     }

-    

+

     android::Parcel* p = android::parcelForJavaObject(env, parcel);

-    

+

     const bool              isMutable = p->readInt32() != 0;

     const SkBitmap::Config  config = (SkBitmap::Config)p->readInt32();

     const int               width = p->readInt32();

     const int               height = p->readInt32();

     const int               rowBytes = p->readInt32();

-    

+

     if (SkBitmap::kARGB_8888_Config != config &&

             SkBitmap::kRGB_565_Config != config &&

             SkBitmap::kARGB_4444_Config != config &&

@@ -355,7 +355,7 @@
             ctable = new SkColorTable(src, count);

         }

     }

-    

+

     if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable)) {

         ctable->safeUnref();

         delete bitmap;

@@ -368,7 +368,7 @@
     bitmap->lockPixels();

     memcpy(bitmap->getPixels(), p->readInplace(size), size);

     bitmap->unlockPixels();

-    

+

     return GraphicsJNI::createBitmap(env, bitmap, isMutable, NULL);

 }

 

@@ -381,7 +381,7 @@
     }

 

     android::Parcel* p = android::parcelForJavaObject(env, parcel);

-    

+

     p->writeInt32(isMutable);

     p->writeInt32(bitmap->config());

     p->writeInt32(bitmap->width());

@@ -413,7 +413,7 @@
                                    jintArray offsetXY) {

     SkIPoint  offset;

     SkBitmap* dst = new SkBitmap;

-    

+

     src->extractAlpha(dst, paint, &offset);

     if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {

         int* array = env->GetIntArrayElements(offsetXY, NULL);

@@ -421,7 +421,7 @@
         array[1] = offset.fY;

         env->ReleaseIntArrayElements(offsetXY, array, 0);

     }

-    

+

     return GraphicsJNI::createBitmap(env, dst, true, NULL);

 }

 

@@ -439,7 +439,7 @@
     if (NULL == src) {

         return 0;

     }

-    

+

     SkColor dst[1];

     proc(dst, src, 1, bitmap->getColorTable());

     return dst[0];

@@ -449,7 +449,7 @@
                              jintArray pixelArray, int offset, int stride,

                              int x, int y, int width, int height) {

     SkAutoLockPixels alp(*bitmap);

-    

+

     ToColorProc proc = ChooseToColorProc(*bitmap);

     if (NULL == proc) {

         return;

@@ -498,7 +498,7 @@
                                       const SkBitmap* bitmap, jobject jbuffer) {

     SkAutoLockPixels alp(*bitmap);

     const void* src = bitmap->getPixels();

-    

+

     if (NULL != src) {

         android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);

 

@@ -511,7 +511,7 @@
                                     const SkBitmap* bitmap, jobject jbuffer) {

     SkAutoLockPixels alp(*bitmap);

     void* dst = bitmap->getPixels();

-    

+

     if (NULL != dst) {

         android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);

         // the java side has already checked that buffer is large enough

@@ -519,6 +519,11 @@
     }

 }

 

+static void Bitmap_prepareToDraw(JNIEnv* env, jobject, SkBitmap* bitmap) {

+    bitmap->lockPixels();

+    bitmap->unlockPixels();

+}

+

 ///////////////////////////////////////////////////////////////////////////////

 

 #include <android_runtime/AndroidRuntime.h>

@@ -552,7 +557,8 @@
     {   "nativeCopyPixelsToBuffer", "(ILjava/nio/Buffer;)V",

                                             (void*)Bitmap_copyPixelsToBuffer },

     {   "nativeCopyPixelsFromBuffer", "(ILjava/nio/Buffer;)V",

-                                            (void*)Bitmap_copyPixelsFromBuffer }

+                                            (void*)Bitmap_copyPixelsFromBuffer },

+    {   "nativePrepareToDraw",      "(I)V", (void*)Bitmap_prepareToDraw }

 };

 

 #define kClassPathName  "android/graphics/Bitmap"

diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 76e6f02..d1fe83e 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -69,6 +69,8 @@
  
     static void reset(JNIEnv* env, jobject clazz, SkPaint* obj) {
         obj->reset();
+        // utf16 is required for java
+        obj->setTextEncoding(SkPaint::kUTF16_TextEncoding);
     }
  
     static void assign(JNIEnv* env, jobject clazz, SkPaint* dst, const SkPaint* src) {
diff --git a/core/jni/android_backup_BackupDataOutput.cpp b/core/jni/android_backup_BackupDataOutput.cpp
index 6362439..d02590e 100644
--- a/core/jni/android_backup_BackupDataOutput.cpp
+++ b/core/jni/android_backup_BackupDataOutput.cpp
@@ -87,11 +87,26 @@
     return err;
 }
 
+static void
+setKeyPrefix_native(JNIEnv* env, jobject clazz, int w, jstring keyPrefixObj)
+{
+    int err;
+    BackupDataWriter* writer = (BackupDataWriter*)w;
+
+    const char* keyPrefixUTF = env->GetStringUTFChars(keyPrefixObj, NULL);
+    String8 keyPrefix(keyPrefixUTF ? keyPrefixUTF : "");
+
+    writer->SetKeyPrefix(keyPrefix);
+
+    env->ReleaseStringUTFChars(keyPrefixObj, keyPrefixUTF);
+}
+
 static const JNINativeMethod g_methods[] = {
     { "ctor", "(Ljava/io/FileDescriptor;)I", (void*)ctor_native },
     { "dtor", "(I)V", (void*)dtor_native },
     { "writeEntityHeader_native", "(ILjava/lang/String;I)I", (void*)writeEntityHeader_native },
     { "writeEntityData_native", "(I[BI)I", (void*)writeEntityData_native },
+    { "setKeyPrefix_native", "(ILjava/lang/String;)V", (void*)setKeyPrefix_native },
 };
 
 int register_android_backup_BackupDataOutput(JNIEnv* env)
diff --git a/core/jni/android_backup_FileBackupHelper.cpp b/core/jni/android_backup_FileBackupHelperBase.cpp
similarity index 69%
rename from core/jni/android_backup_FileBackupHelper.cpp
rename to core/jni/android_backup_FileBackupHelperBase.cpp
index 418db8a..8225a36 100644
--- a/core/jni/android_backup_FileBackupHelper.cpp
+++ b/core/jni/android_backup_FileBackupHelperBase.cpp
@@ -29,6 +29,18 @@
 static jfieldID s_descriptorField = 0;
 
 static int
+ctor(JNIEnv* env, jobject clazz)
+{
+    return (int)new RestoreHelperBase();
+}
+
+static void
+dtor(JNIEnv* env, jobject clazz, jint ptr)
+{
+    delete (RestoreHelperBase*)ptr;
+}
+
+static int
 performBackup_native(JNIEnv* env, jobject clazz, jobject oldState, int data,
         jobject newState, jobjectArray files, jobjectArray keys)
 {
@@ -66,13 +78,48 @@
     return err;
 }
 
+
+static int
+writeFile_native(JNIEnv* env, jobject clazz, jint ptr, jstring filenameObj, int backupReaderPtr)
+{
+    int err;
+    RestoreHelperBase* restore = (RestoreHelperBase*)ptr;
+    BackupDataReader* reader = (BackupDataReader*)backupReaderPtr;
+    char const* filename;
+
+    filename = env->GetStringUTFChars(filenameObj, NULL);
+
+    err = restore->WriteFile(String8(filename), reader);
+
+    env->ReleaseStringUTFChars(filenameObj, filename);
+
+    return err;
+}
+
+static int
+writeSnapshot_native(JNIEnv* env, jobject clazz, jint ptr, jobject fileDescriptor)
+{
+    int err;
+
+    RestoreHelperBase* restore = (RestoreHelperBase*)ptr;
+    int fd = env->GetIntField(fileDescriptor, s_descriptorField);
+
+    err = restore->WriteSnapshot(fd);
+
+    return err;
+}
+
 static const JNINativeMethod g_methods[] = {
+    { "ctor", "()I", (void*)ctor },
+    { "dtor", "(I)V", (void*)dtor },
     { "performBackup_native",
        "(Ljava/io/FileDescriptor;ILjava/io/FileDescriptor;[Ljava/lang/String;[Ljava/lang/String;)I",
        (void*)performBackup_native },
+    { "writeFile_native", "(ILjava/lang/String;I)I", (void*)writeFile_native },
+    { "writeSnapshot_native", "(ILjava/io/FileDescriptor;)I", (void*)writeSnapshot_native },
 };
 
-int register_android_backup_FileBackupHelper(JNIEnv* env)
+int register_android_backup_FileBackupHelperBase(JNIEnv* env)
 {
     jclass clazz;
 
@@ -82,7 +129,7 @@
     LOG_FATAL_IF(s_descriptorField == NULL,
             "Unable to find descriptor field in java.io.FileDescriptor");
     
-    return AndroidRuntime::registerNativeMethods(env, "android/backup/FileBackupHelper",
+    return AndroidRuntime::registerNativeMethods(env, "android/backup/FileBackupHelperBase",
             g_methods, NELEM(g_methods));
 }
 
diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp
old mode 100644
new mode 100755
index 5c4fb22..bf0bd65
--- a/core/jni/android_location_GpsLocationProvider.cpp
+++ b/core/jni/android_location_GpsLocationProvider.cpp
@@ -336,13 +336,15 @@
 }
 
 static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj,
-        jint type, jint addr, jint port)
+        jint type, jstring hostname, jint port)
 {
     if (!sAGpsInterface) {
         sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
     }
     if (sAGpsInterface) {
-        sAGpsInterface->set_server(type, addr, port);
+        const char *c_hostname = env->GetStringUTFChars(hostname, NULL);
+        sAGpsInterface->set_server(type, c_hostname, port);
+        env->ReleaseStringUTFChars(hostname, c_hostname);
     }
 }
 
@@ -365,7 +367,7 @@
     {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open},
     {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
     {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
-    {"native_set_agps_server", "(III)V", (void*)android_location_GpsLocationProvider_set_agps_server},
+    {"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server},
 };
 
 int register_android_location_GpsLocationProvider(JNIEnv* env)
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 75a961c..0857cb3 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -149,6 +149,19 @@
     NULL, agent_event_filter, NULL, NULL, NULL, NULL
 };
 
+static unsigned int unix_events_to_dbus_flags(short events) {
+    return (events & DBUS_WATCH_READABLE ? POLLIN : 0) |
+           (events & DBUS_WATCH_WRITABLE ? POLLOUT : 0) |
+           (events & DBUS_WATCH_ERROR ? POLLERR : 0) |
+           (events & DBUS_WATCH_HANGUP ? POLLHUP : 0);
+}
+
+static short dbus_flags_to_unix_events(unsigned int flags) {
+    return (flags & POLLIN ? DBUS_WATCH_READABLE : 0) |
+           (flags & POLLOUT ? DBUS_WATCH_WRITABLE : 0) |
+           (flags & POLLERR ? DBUS_WATCH_ERROR : 0) |
+           (flags & POLLHUP ? DBUS_WATCH_HANGUP : 0);
+}
 
 static jboolean setUpEventLoop(native_data_t *nat) {
     LOGV(__FUNCTION__);
@@ -408,8 +421,7 @@
     read(nat->controlFdR, &newFD, sizeof(int));
     read(nat->controlFdR, &flags, sizeof(unsigned int));
     read(nat->controlFdR, &watch, sizeof(DBusWatch *));
-    int events = (flags & DBUS_WATCH_READABLE ? POLLIN : 0)
-            | (flags & DBUS_WATCH_WRITABLE ? POLLOUT : 0);
+    short events = dbus_flags_to_unix_events(flags);
 
     for (int y = 0; y<nat->pollMemberCount; y++) {
         if ((nat->pollData[y].fd == newFD) &&
@@ -453,8 +465,7 @@
 
     read(nat->controlFdR, &removeFD, sizeof(int));
     read(nat->controlFdR, &flags, sizeof(unsigned int));
-    int events = (flags & DBUS_WATCH_READABLE ? POLLIN : 0)
-            | (flags & DBUS_WATCH_WRITABLE ? POLLOUT : 0);
+    short events = dbus_flags_to_unix_events(flags);
 
     for (int y = 0; y < nat->pollMemberCount; y++) {
         if ((nat->pollData[y].fd == removeFD) &&
@@ -518,13 +529,12 @@
                     }
                 }
             } else {
-                  int event = nat->pollData[i].revents;
-                  int flags = (event & POLLIN ? DBUS_WATCH_READABLE : 0) |
-                              (event & POLLOUT ? DBUS_WATCH_WRITABLE : 0);
-                  dbus_watch_handle(nat->watchData[i], event);
-                  nat->pollData[i].revents = 0;
-                  // can only do one - it may have caused a 'remove'
-                  break;
+                short events = nat->pollData[i].revents;
+                unsigned int flags = unix_events_to_dbus_flags(events);
+                dbus_watch_handle(nat->watchData[i], flags);
+                nat->pollData[i].revents = 0;
+                // can only do one - it may have caused a 'remove'
+                break;
             }
         }
         while (dbus_connection_dispatch(nat->conn) == 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c1017d4..0c90769 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -175,6 +175,22 @@
         android:label="@string/permlab_writeDictionary"
         android:description="@string/permdesc_writeDictionary" />
 
+    <!-- Allows an application to read (but not write) the user's
+        browsing history and bookmarks. -->
+    <permission android:name="android.permission.READ_HISTORY_BOOKMARKS"
+        android:permissionGroup="android.permission-group.PERSONAL_INFO"
+        android:label="@string/permlab_readHistoryBookmarks"
+        android:description="@string/permdesc_readHistoryBookmarks"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows an application to write (but not read) the user's
+        browsing history and bookmarks. -->
+    <permission android:name="android.permission.WRITE_HISTORY_BOOKMARKS"
+        android:permissionGroup="android.permission-group.PERSONAL_INFO"
+        android:label="@string/permlab_writeHistoryBookmarks"
+        android:description="@string/permdesc_writeHistoryBookmarks"
+        android:protectionLevel="dangerous" />
+
     <!-- ======================================= -->
     <!-- Permissions for accessing location info -->
     <!-- ======================================= -->
diff --git a/core/res/res/layout/search_bar.xml b/core/res/res/layout/search_bar.xml
index 7b7f8a6..54ab6de 100644
--- a/core/res/res/layout/search_bar.xml
+++ b/core/res/res/layout/search_bar.xml
@@ -73,6 +73,7 @@
                 android:paddingRight="6dip"
                 android:drawablePadding="2dip"
                 android:singleLine="true"
+                android:ellipsize="end"
                 android:inputType="text|textAutoComplete"
                 android:dropDownWidth="fill_parent"
                 android:dropDownAnchor="@id/search_plate"
diff --git a/core/res/res/values-bg-rBG/donottranslate-cldr.xml b/core/res/res/values-bg-rBG/donottranslate-cldr.xml
index cda072a..b8b50cc 100644
--- a/core/res/res/values-bg-rBG/donottranslate-cldr.xml
+++ b/core/res/res/values-bg-rBG/donottranslate-cldr.xml
@@ -107,19 +107,19 @@
     <string name="abbrev_month_day_year">%d.%m.%Y</string>
     <string name="month_day">%-e %B</string>
     <string name="month">%-B</string>
-    <string name="month_year">%Y %B</string>
+    <string name="month_year">%B %Y</string>
     <string name="abbrev_month_day">%-e %b</string>
-    <string name="abbrev_month">%-b</string>
-    <string name="abbrev_month_year">%Y %b</string>
+    <string name="abbrev_month">%b</string>
+    <string name="abbrev_month_year">%b %Y</string>
     <string name="time1_time2">%1$s - %2$s</string>
     <string name="date1_date2">%2$s - %5$s</string>
     <string name="numeric_md1_md2">%3$s.%2$s - %8$s.%7$s</string>
     <string name="numeric_wday1_md1_wday2_md2">%3$s.%2$s, %1$s - %8$s.%7$s, %6$s</string>
     <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s - %8$s.%7$s.%9$s</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%3$s.%2$s.%4$s, %1$s - %8$s.%7$s.%9$s, %6$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s - %10$s %6$s, %9$s-%7$s-%8$s</string>
-    <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s - %10$s %7$s-%8$s</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s - %10$s %6$s, %7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %3$s.%2$s.%4$s, %1$s - %10$s %8$s.%7$s.%9$s, %6$s</string>
+    <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s - %10$s %8$s.%7$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %3$s.%2$s, %1$s - %10$s %8$s.%7$s, %6$s</string>
     <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string>
     <string name="wday1_date1_time1_wday2_date2_time2">%3$s %2$s, %1$s - %6$s %5$s, %4$s</string>
     <string name="wday1_date1_wday2_date2">%2$s, %1$s - %5$s, %4$s</string>
@@ -135,9 +135,9 @@
     <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %3$s %2$s, %1$s - %10$s %8$s %7$s, %6$s</string>
     <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string>
     <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string>
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string>
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string>
-    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s - %6$s, %9$s %7$s %8$s</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %3$s %2$s %4$s, %1$s - %10$s %8$s %7$s %9$s, %6$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %3$s %2$s %4$s, %1$s - %10$s %8$s %7$s %9$s, %6$s</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">%3$s %2$s %4$s, %1$s - %8$s %7$s %9$s, %6$s</string>
     <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
     <string name="same_month_wday1_md1_wday2_md2">%3$s %2$s, %1$s - %8$s %7$s, %6$s</string>
     <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
diff --git a/core/res/res/values-cs-rCZ/donottranslate-cldr.xml b/core/res/res/values-cs-rCZ/donottranslate-cldr.xml
index 2e348b8..41f5dea 100644
--- a/core/res/res/values-cs-rCZ/donottranslate-cldr.xml
+++ b/core/res/res/values-cs-rCZ/donottranslate-cldr.xml
@@ -107,7 +107,7 @@
     <string name="abbrev_month_day_year">%-e.%-m.%Y</string>
     <string name="month_day">%-e. %B</string>
     <string name="month">%-B</string>
-    <string name="month_year">%Y %B</string>
+    <string name="month_year">%-B %Y</string>
     <string name="abbrev_month_day">%-e.%-m</string>
     <string name="abbrev_month">%-B</string>
     <string name="abbrev_month_year">%-B %Y</string>
@@ -117,9 +117,9 @@
     <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s. - %6$s, %8$s.%7$s.</string>
     <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s - %8$s.%7$s.%9$s</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s - %10$s %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s</string>
     <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s - %10$s %8$s.%7$s</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s - %10$s %6$s, %7$s-%8$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s.</string>
     <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string>
     <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string>
     <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
diff --git a/core/res/res/values-cs/donottranslate-cldr.xml b/core/res/res/values-cs/donottranslate-cldr.xml
index 2e348b8..41f5dea 100644
--- a/core/res/res/values-cs/donottranslate-cldr.xml
+++ b/core/res/res/values-cs/donottranslate-cldr.xml
@@ -107,7 +107,7 @@
     <string name="abbrev_month_day_year">%-e.%-m.%Y</string>
     <string name="month_day">%-e. %B</string>
     <string name="month">%-B</string>
-    <string name="month_year">%Y %B</string>
+    <string name="month_year">%-B %Y</string>
     <string name="abbrev_month_day">%-e.%-m</string>
     <string name="abbrev_month">%-B</string>
     <string name="abbrev_month_year">%-B %Y</string>
@@ -117,9 +117,9 @@
     <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s. - %6$s, %8$s.%7$s.</string>
     <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s - %8$s.%7$s.%9$s</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s - %10$s %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s</string>
     <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s - %10$s %8$s.%7$s</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s - %10$s %6$s, %7$s-%8$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s.</string>
     <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string>
     <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string>
     <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
diff --git a/core/res/res/values-da-rDK/donottranslate-cldr.xml b/core/res/res/values-da-rDK/donottranslate-cldr.xml
index 8cef5b2..2d0db93 100644
--- a/core/res/res/values-da-rDK/donottranslate-cldr.xml
+++ b/core/res/res/values-da-rDK/donottranslate-cldr.xml
@@ -106,7 +106,7 @@
     <string name="time_date">%1$s %3$s</string>
     <string name="abbrev_month_day_year">%d/%m/%Y</string>
     <string name="month_day">%-e. %B</string>
-    <string name="month">%b</string>
+    <string name="month">%B</string>
     <string name="month_year">%B %Y</string>
     <string name="abbrev_month_day">%-e. %b</string>
     <string name="abbrev_month">%b</string>
diff --git a/core/res/res/values-de-rAT/donottranslate-cldr.xml b/core/res/res/values-de-rAT/donottranslate-cldr.xml
index 559e1ee..d8d6ba6 100644
--- a/core/res/res/values-de-rAT/donottranslate-cldr.xml
+++ b/core/res/res/values-de-rAT/donottranslate-cldr.xml
@@ -75,7 +75,7 @@
     <string name="month_day">%-e. %B</string>
     <string name="month">%-B</string>
     <string name="month_year">%B %Y</string>
-    <string name="abbrev_month_day">%-e. %b</string>
+    <string name="abbrev_month_day">%d. %b</string>
     <string name="abbrev_month">%-b</string>
     <string name="abbrev_month_year">%b %Y</string>
     <string name="time1_time2">%1$s - %2$s</string>
@@ -88,25 +88,25 @@
     <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s. - %10$s %8$s.%7$s.</string>
     <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s.</string>
     <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string>
-    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s - %6$s %4$s %5$s</string>
-    <string name="wday1_date1_wday2_date2">%1$s %2$s - %4$s %5$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
     <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
-    <string name="time_wday_date">%1$s %2$s %3$s</string>
-    <string name="wday_date">%2$s %3$s</string>
+    <string name="time_wday_date">%1$s %2$s, %3$s</string>
+    <string name="wday_date">%2$s, %3$s</string>
     <string name="time_wday">%1$s %2$s</string>
     <string name="same_year_md1_md2">%3$s. %2$s - %8$s. %7$s</string>
-    <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s. %2$s - %6$s %8$s. %7$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s</string>
     <string name="same_year_md1_time1_md2_time2">%5$s %3$s. %2$s - %10$s %8$s. %7$s</string>
     <string name="same_month_md1_time1_md2_time2">%5$s %3$s. %2$s - %10$s %8$s. %7$s</string>
-    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s</string>
-    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s</string>
     <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s</string>
     <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s</string>
     <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s</string>
     <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$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>
     <string name="same_month_md1_md2">%3$s.-%8$s. %2$s</string>
-    <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s. %2$s - %6$s %8$s. %7$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s</string>
     <string name="same_year_mdy1_mdy2">%3$s. %2$s - %8$s. %7$s %9$s</string>
     <string name="same_month_mdy1_mdy2">%3$s.-%8$s. %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s</string>
diff --git a/core/res/res/values-en-rAU/donottranslate-cldr.xml b/core/res/res/values-en-rAU/donottranslate-cldr.xml
index 5d1a8f6..9811b68 100644
--- a/core/res/res/values-en-rAU/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rAU/donottranslate-cldr.xml
@@ -108,8 +108,8 @@
     <string name="month_day">%-e %B</string>
     <string name="month">%-B</string>
     <string name="month_year">%B %Y</string>
-    <string name="abbrev_month_day">%b %-e</string>
-    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month_day">%-e %b</string>
+    <string name="abbrev_month">%b</string>
     <string name="abbrev_month_year">%b %Y</string>
     <string name="time1_time2">%1$s - %2$s</string>
     <string name="date1_date2">%2$s - %5$s</string>
@@ -117,9 +117,9 @@
     <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s/%2$s - %6$s, %8$s/%7$s</string>
     <string name="numeric_mdy1_mdy2">%3$s/%2$s/%4$s - %8$s/%7$s/%9$s</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s/%2$s/%4$s - %6$s, %8$s/%7$s/%9$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s/%3$s/%4$s, %5$s - %6$s, %7$s/%8$s/%9$s, %10$s</string>
-    <string name="numeric_md1_time1_md2_time2">%2$s/%3$s, %5$s - %7$s/%8$s, %10$s</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%1$s, %2$s/%3$s, %5$s - %6$s, %7$s/%8$s, %10$s</string>
+    <string name="numeric_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="numeric_md1_time1_md2_time2">%3$s/%2$s, %5$s - %8$s/%7$s, %10$s</string>
+    <string name="numeric_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="numeric_mdy1_time1_mdy2_time2">%3$s/%2$s/%4$s, %5$s - %8$s/%7$s/%9$s, %10$s</string>
     <string name="wday1_date1_time1_wday2_date2_time2">%1$s, %2$s, %3$s - %4$s, %5$s, %6$s</string>
     <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
@@ -128,18 +128,18 @@
     <string name="wday_date">%2$s, %3$s</string>
     <string name="time_wday">%1$s, %2$s</string>
     <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string>
-    <string name="same_year_wday1_md1_wday2_md2">%1$s, %2$s %3$s - %6$s, %7$s %8$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s %2$s - %6$s, %8$s %7$s</string>
     <string name="same_year_md1_time1_md2_time2">%3$s %2$s, %5$s - %8$s %7$s, %10$s</string>
     <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, %2$s %3$s, %5$s - %6$s, %7$s %8$s, %10$s</string>
-    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%1$s, %2$s %3$s, %5$s - %6$s, %7$s %8$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">%3$s %2$s %4$s, %5$s - %8$s %7$s %9$s, %10$s</string>
     <string name="same_month_mdy1_time1_mdy2_time2">%3$s %2$s %4$s, %5$s - %8$s %7$s %9$s, %10$s</string>
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s %3$s, %4$s, %5$s - %6$s, %7$s %8$s, %9$s, %10$s</string>
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s %3$s, %4$s, %5$s - %6$s, %7$s %8$s, %9$s, %10$s</string>
-    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s, %4$s - %6$s, %7$s %8$s, %9$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>
     <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
-    <string name="same_month_wday1_md1_wday2_md2">%1$s, %2$s %3$s - %6$s, %7$s %8$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s %2$s - %6$s, %8$s %7$s</string>
     <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
diff --git a/core/res/res/values-en-rCA/donottranslate-cldr.xml b/core/res/res/values-en-rCA/donottranslate-cldr.xml
index 5d7300e..1e250c7 100644
--- a/core/res/res/values-en-rCA/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rCA/donottranslate-cldr.xml
@@ -109,7 +109,7 @@
     <string name="month">%-B</string>
     <string name="month_year">%B %Y</string>
     <string name="abbrev_month_day">%b %-e</string>
-    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month">%b</string>
     <string name="abbrev_month_year">%b %Y</string>
     <string name="time1_time2">%1$s - %2$s</string>
     <string name="date1_date2">%2$s - %5$s</string>
@@ -117,9 +117,9 @@
     <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s-%3$s - %6$s, %7$s-%8$s</string>
     <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s - %9$s-%7$s-%8$s</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %4$s-%2$s-%3$s - %6$s, %9$s-%7$s-%8$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s/%3$s/%4$s, %5$s - %6$s, %7$s/%8$s/%9$s, %10$s</string>
-    <string name="numeric_md1_time1_md2_time2">%2$s/%3$s, %5$s - %7$s/%8$s, %10$s</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%1$s, %2$s/%3$s, %5$s - %6$s, %7$s/%8$s, %10$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %4$s-%2$s-%3$s, %5$s - %6$s, %9$s-%7$s-%8$s, %10$s</string>
+    <string name="numeric_md1_time1_md2_time2">%2$s-%3$s, %5$s - %7$s-%8$s, %10$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%1$s, %2$s-%3$s, %5$s - %6$s, %7$s-%8$s, %10$s</string>
     <string name="numeric_mdy1_time1_mdy2_time2">%4$s-%2$s-%3$s, %5$s - %9$s-%7$s-%8$s, %10$s</string>
     <string name="wday1_date1_time1_wday2_date2_time2">%1$s, %2$s, %3$s - %4$s, %5$s, %6$s</string>
     <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
diff --git a/core/res/res/values-en-rGB/donottranslate-cldr.xml b/core/res/res/values-en-rGB/donottranslate-cldr.xml
index b115c6e..0e3e035 100644
--- a/core/res/res/values-en-rGB/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rGB/donottranslate-cldr.xml
@@ -108,8 +108,8 @@
     <string name="month_day">%-e %B</string>
     <string name="month">%-B</string>
     <string name="month_year">%B %Y</string>
-    <string name="abbrev_month_day">%b %-e</string>
-    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month_day">%-e %b</string>
+    <string name="abbrev_month">%b</string>
     <string name="abbrev_month_year">%b %Y</string>
     <string name="time1_time2">%1$s - %2$s</string>
     <string name="date1_date2">%2$s - %5$s</string>
@@ -121,11 +121,11 @@
     <string name="numeric_md1_time1_md2_time2">%3$s/%2$s, %5$s - %8$s/%7$s, %10$s</string>
     <string name="numeric_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="numeric_mdy1_time1_mdy2_time2">%3$s/%2$s/%4$s, %5$s - %8$s/%7$s/%9$s, %10$s</string>
-    <string name="wday1_date1_time1_wday2_date2_time2">%1$s, %2$s, %3$s - %4$s, %5$s, %6$s</string>
-    <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%1$s %2$s, %3$s - %4$s %5$s, %6$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s %2$s - %4$s %5$s</string>
     <string name="date1_time1_date2_time2">%2$s, %3$s - %5$s, %6$s</string>
-    <string name="time_wday_date">%1$s, %2$s, %3$s</string>
-    <string name="wday_date">%2$s, %3$s</string>
+    <string name="time_wday_date">%1$s, %2$s %3$s</string>
+    <string name="wday_date">%2$s %3$s</string>
     <string name="time_wday">%1$s, %2$s</string>
     <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string>
     <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
@@ -135,9 +135,9 @@
     <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">%3$s %2$s %4$s, %5$s - %8$s %7$s %9$s, %10$s</string>
     <string name="same_month_mdy1_time1_mdy2_time2">%3$s %2$s %4$s, %5$s - %8$s %7$s %9$s, %10$s</string>
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s %3$s, %4$s, %5$s - %6$s, %7$s %8$s, %9$s, %10$s</string>
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s %3$s, %4$s, %5$s - %6$s, %7$s %8$s, %9$s, %10$s</string>
-    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s, %4$s - %6$s, %7$s %8$s, %9$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>
     <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
     <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
     <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
diff --git a/core/res/res/values-en-rIE/donottranslate-cldr.xml b/core/res/res/values-en-rIE/donottranslate-cldr.xml
index 15fc8e8..2e59dcf 100644
--- a/core/res/res/values-en-rIE/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rIE/donottranslate-cldr.xml
@@ -108,8 +108,8 @@
     <string name="month_day">%-e %B</string>
     <string name="month">%-B</string>
     <string name="month_year">%B %Y</string>
-    <string name="abbrev_month_day">%b %-e</string>
-    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month_day">%-e %b</string>
+    <string name="abbrev_month">%b</string>
     <string name="abbrev_month_year">%b %Y</string>
     <string name="time1_time2">%1$s - %2$s</string>
     <string name="date1_date2">%2$s - %5$s</string>
@@ -121,25 +121,25 @@
     <string name="numeric_md1_time1_md2_time2">%3$s/%2$s, %5$s - %8$s/%7$s, %10$s</string>
     <string name="numeric_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="numeric_mdy1_time1_mdy2_time2">%3$s/%2$s/%4$s, %5$s - %8$s/%7$s/%9$s, %10$s</string>
-    <string name="wday1_date1_time1_wday2_date2_time2">%1$s, %2$s, %3$s - %4$s, %5$s, %6$s</string>
-    <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%1$s %2$s, %3$s - %4$s %5$s, %6$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s %2$s - %4$s %5$s</string>
     <string name="date1_time1_date2_time2">%2$s, %3$s - %5$s, %6$s</string>
-    <string name="time_wday_date">%1$s, %2$s, %3$s</string>
-    <string name="wday_date">%2$s, %3$s</string>
+    <string name="time_wday_date">%1$s, %2$s %3$s</string>
+    <string name="wday_date">%2$s %3$s</string>
     <string name="time_wday">%1$s, %2$s</string>
     <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string>
-    <string name="same_year_wday1_md1_wday2_md2">%1$s, %2$s %3$s - %6$s, %7$s %8$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
     <string name="same_year_md1_time1_md2_time2">%3$s %2$s, %5$s - %8$s %7$s, %10$s</string>
     <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, %2$s %3$s, %5$s - %6$s, %7$s %8$s, %10$s</string>
-    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%1$s, %2$s %3$s, %5$s - %6$s, %7$s %8$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">%3$s %2$s %4$s, %5$s - %8$s %7$s %9$s, %10$s</string>
     <string name="same_month_mdy1_time1_mdy2_time2">%3$s %2$s %4$s, %5$s - %8$s %7$s %9$s, %10$s</string>
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s %3$s, %4$s, %5$s - %6$s, %7$s %8$s, %9$s, %10$s</string>
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s %3$s, %4$s, %5$s - %6$s, %7$s %8$s, %9$s, %10$s</string>
-    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s, %4$s - %6$s, %7$s %8$s, %9$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>
     <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
-    <string name="same_month_wday1_md1_wday2_md2">%1$s, %2$s %3$s - %6$s, %7$s %8$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
     <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
diff --git a/core/res/res/values-en-rIN/donottranslate-cldr.xml b/core/res/res/values-en-rIN/donottranslate-cldr.xml
index 2507ee8..e39a59a 100644
--- a/core/res/res/values-en-rIN/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rIN/donottranslate-cldr.xml
@@ -108,8 +108,8 @@
     <string name="month_day">%-e %B</string>
     <string name="month">%-B</string>
     <string name="month_year">%B %Y</string>
-    <string name="abbrev_month_day">%b %-e</string>
-    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month_day">%-e %b</string>
+    <string name="abbrev_month">%b</string>
     <string name="abbrev_month_year">%b %Y</string>
     <string name="time1_time2">%1$s - %2$s</string>
     <string name="date1_date2">%2$s - %5$s</string>
@@ -117,29 +117,29 @@
     <string name="numeric_wday1_md1_wday2_md2">%1$s %3$s/%2$s - %6$s %8$s/%7$s</string>
     <string name="numeric_mdy1_mdy2">%3$s/%2$s/%4$s - %8$s/%7$s/%9$s</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s %3$s/%2$s/%4$s - %6$s %8$s/%7$s/%9$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s/%3$s/%4$s, %5$s - %6$s, %7$s/%8$s/%9$s, %10$s</string>
-    <string name="numeric_md1_time1_md2_time2">%2$s/%3$s, %5$s - %7$s/%8$s, %10$s</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%1$s, %2$s/%3$s, %5$s - %6$s, %7$s/%8$s, %10$s</string>
+    <string name="numeric_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="numeric_md1_time1_md2_time2">%3$s/%2$s, %5$s - %8$s/%7$s, %10$s</string>
+    <string name="numeric_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="numeric_mdy1_time1_mdy2_time2">%3$s/%2$s/%4$s, %5$s - %8$s/%7$s/%9$s, %10$s</string>
-    <string name="wday1_date1_time1_wday2_date2_time2">%1$s, %2$s, %3$s - %4$s, %5$s, %6$s</string>
-    <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%1$s %2$s, %3$s - %4$s %5$s, %6$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s %2$s - %4$s %5$s</string>
     <string name="date1_time1_date2_time2">%2$s, %3$s - %5$s, %6$s</string>
-    <string name="time_wday_date">%1$s, %2$s, %3$s</string>
-    <string name="wday_date">%2$s, %3$s</string>
+    <string name="time_wday_date">%1$s, %2$s %3$s</string>
+    <string name="wday_date">%2$s %3$s</string>
     <string name="time_wday">%1$s, %2$s</string>
     <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string>
-    <string name="same_year_wday1_md1_wday2_md2">%1$s, %2$s %3$s - %6$s, %7$s %8$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
     <string name="same_year_md1_time1_md2_time2">%3$s %2$s, %5$s - %8$s %7$s, %10$s</string>
     <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, %2$s %3$s, %5$s - %6$s, %7$s %8$s, %10$s</string>
-    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%1$s, %2$s %3$s, %5$s - %6$s, %7$s %8$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">%3$s %2$s %4$s, %5$s - %8$s %7$s %9$s, %10$s</string>
     <string name="same_month_mdy1_time1_mdy2_time2">%3$s %2$s %4$s, %5$s - %8$s %7$s %9$s, %10$s</string>
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s %3$s, %4$s, %5$s - %6$s, %7$s %8$s, %9$s, %10$s</string>
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s %3$s, %4$s, %5$s - %6$s, %7$s %8$s, %9$s, %10$s</string>
-    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s, %4$s - %6$s, %7$s %8$s, %9$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>
     <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
-    <string name="same_month_wday1_md1_wday2_md2">%1$s, %2$s %3$s - %6$s, %7$s %8$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
     <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
diff --git a/core/res/res/values-en-rNZ/donottranslate-cldr.xml b/core/res/res/values-en-rNZ/donottranslate-cldr.xml
index 07d4fe8..3a8b50b 100644
--- a/core/res/res/values-en-rNZ/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rNZ/donottranslate-cldr.xml
@@ -108,8 +108,8 @@
     <string name="month_day">%-e %B</string>
     <string name="month">%-B</string>
     <string name="month_year">%B %Y</string>
-    <string name="abbrev_month_day">%b %-e</string>
-    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month_day">%-e %b</string>
+    <string name="abbrev_month">%b</string>
     <string name="abbrev_month_year">%b %Y</string>
     <string name="time1_time2">%1$s - %2$s</string>
     <string name="date1_date2">%2$s - %5$s</string>
@@ -117,9 +117,9 @@
     <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s/%2$s - %6$s, %8$s/%7$s</string>
     <string name="numeric_mdy1_mdy2">%3$s/%2$s/%4$s - %8$s/%7$s/%9$s</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s/%2$s/%4$s - %6$s, %8$s/%7$s/%9$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s/%3$s/%4$s, %5$s - %6$s, %7$s/%8$s/%9$s, %10$s</string>
+    <string name="numeric_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="numeric_md1_time1_md2_time2">%3$s/%2$s, %5$s - %8$s/%7$s, %10$s</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%1$s, %2$s/%3$s, %5$s - %6$s, %7$s/%8$s, %10$s</string>
+    <string name="numeric_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="numeric_mdy1_time1_mdy2_time2">%3$s/%2$s/%4$s, %5$s - %8$s/%7$s/%9$s, %10$s</string>
     <string name="wday1_date1_time1_wday2_date2_time2">%1$s, %2$s, %3$s - %4$s, %5$s, %6$s</string>
     <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
@@ -128,18 +128,18 @@
     <string name="wday_date">%2$s, %3$s</string>
     <string name="time_wday">%1$s, %2$s</string>
     <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string>
-    <string name="same_year_wday1_md1_wday2_md2">%1$s, %2$s %3$s - %6$s, %7$s %8$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s %2$s - %6$s, %8$s %7$s</string>
     <string name="same_year_md1_time1_md2_time2">%3$s %2$s, %5$s - %8$s %7$s, %10$s</string>
     <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, %2$s %3$s, %5$s - %6$s, %7$s %8$s, %10$s</string>
-    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%1$s, %2$s %3$s, %5$s - %6$s, %7$s %8$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">%3$s %2$s %4$s, %5$s - %8$s %7$s %9$s, %10$s</string>
     <string name="same_month_mdy1_time1_mdy2_time2">%3$s %2$s %4$s, %5$s - %8$s %7$s %9$s, %10$s</string>
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s %3$s, %4$s, %5$s - %6$s, %7$s %8$s, %9$s, %10$s</string>
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s %3$s, %4$s, %5$s - %6$s, %7$s %8$s, %9$s, %10$s</string>
-    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s, %4$s - %6$s, %7$s %8$s, %9$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>
     <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
-    <string name="same_month_wday1_md1_wday2_md2">%1$s, %2$s %3$s - %6$s, %7$s %8$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s %2$s - %6$s, %8$s %7$s</string>
     <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
diff --git a/core/res/res/values-en-rZA/donottranslate-cldr.xml b/core/res/res/values-en-rZA/donottranslate-cldr.xml
index 9e8681b..2e2d608 100644
--- a/core/res/res/values-en-rZA/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rZA/donottranslate-cldr.xml
@@ -108,8 +108,8 @@
     <string name="month_day">%B %-e</string>
     <string name="month">%-B</string>
     <string name="month_year">%B %Y</string>
-    <string name="abbrev_month_day">%b %-e</string>
-    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month_day">%d %b</string>
+    <string name="abbrev_month">%b</string>
     <string name="abbrev_month_year">%b %Y</string>
     <string name="time1_time2">%1$s - %2$s</string>
     <string name="date1_date2">%2$s - %5$s</string>
@@ -117,29 +117,29 @@
     <string name="numeric_wday1_md1_wday2_md2">%1$s %2$s/%3$s - %6$s %7$s/%8$s</string>
     <string name="numeric_mdy1_mdy2">%4$s/%2$s/%3$s - %9$s/%7$s/%8$s</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s %4$s/%2$s/%3$s - %6$s %9$s/%7$s/%8$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s/%3$s/%4$s, %5$s - %6$s, %7$s/%8$s/%9$s, %10$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%1$s %4$s/%2$s/%3$s, %5$s - %6$s %9$s/%7$s/%8$s, %10$s</string>
     <string name="numeric_md1_time1_md2_time2">%2$s/%3$s, %5$s - %7$s/%8$s, %10$s</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%1$s, %2$s/%3$s, %5$s - %6$s, %7$s/%8$s, %10$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%1$s %2$s/%3$s, %5$s - %6$s %7$s/%8$s, %10$s</string>
     <string name="numeric_mdy1_time1_mdy2_time2">%4$s/%2$s/%3$s, %5$s - %9$s/%7$s/%8$s, %10$s</string>
-    <string name="wday1_date1_time1_wday2_date2_time2">%1$s, %2$s, %3$s - %4$s, %5$s, %6$s</string>
-    <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%1$s %2$s, %3$s - %4$s %5$s, %6$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s %2$s - %4$s %5$s</string>
     <string name="date1_time1_date2_time2">%2$s, %3$s - %5$s, %6$s</string>
-    <string name="time_wday_date">%1$s, %2$s, %3$s</string>
-    <string name="wday_date">%2$s, %3$s</string>
+    <string name="time_wday_date">%1$s, %2$s %3$s</string>
+    <string name="wday_date">%2$s %3$s</string>
     <string name="time_wday">%1$s, %2$s</string>
     <string name="same_year_md1_md2">%2$s %3$s - %7$s %8$s</string>
-    <string name="same_year_wday1_md1_wday2_md2">%1$s, %2$s %3$s - %6$s, %7$s %8$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
     <string name="same_year_md1_time1_md2_time2">%2$s %3$s, %5$s - %7$s %8$s, %10$s</string>
     <string name="same_month_md1_time1_md2_time2">%2$s %3$s, %5$s - %7$s %8$s, %10$s</string>
-    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%1$s, %2$s %3$s, %5$s - %6$s, %7$s %8$s, %10$s</string>
-    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%1$s, %2$s %3$s, %5$s - %6$s, %7$s %8$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">%3$s %2$s %4$s, %5$s - %8$s %7$s %9$s, %10$s</string>
     <string name="same_month_mdy1_time1_mdy2_time2">%3$s %2$s %4$s, %5$s - %8$s %7$s %9$s, %10$s</string>
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s %3$s, %4$s, %5$s - %6$s, %7$s %8$s, %9$s, %10$s</string>
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %2$s %3$s, %4$s, %5$s - %6$s, %7$s %8$s, %9$s, %10$s</string>
-    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s, %4$s - %6$s, %7$s %8$s, %9$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>
     <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
-    <string name="same_month_wday1_md1_wday2_md2">%1$s, %2$s %3$s - %6$s, %7$s %8$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
     <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
diff --git a/core/res/res/values-es-rUS/donottranslate-cldr.xml b/core/res/res/values-es-rUS/donottranslate-cldr.xml
index 24923c3..d6d8954 100644
--- a/core/res/res/values-es-rUS/donottranslate-cldr.xml
+++ b/core/res/res/values-es-rUS/donottranslate-cldr.xml
@@ -108,18 +108,18 @@
     <string name="month_day">%-e de %B</string>
     <string name="month">%-B</string>
     <string name="month_year">%B de %Y</string>
-    <string name="abbrev_month_day">%-e %b</string>
-    <string name="abbrev_month">%-b</string>
-    <string name="abbrev_month_year">%b %Y</string>
+    <string name="abbrev_month_day">%-e de %b</string>
+    <string name="abbrev_month">%b</string>
+    <string name="abbrev_month_year">%b de %Y</string>
     <string name="time1_time2">%1$s a el %2$s</string>
     <string name="date1_date2">%2$s a el %5$s</string>
     <string name="numeric_md1_md2">%2$s/%3$s - %7$s/%8$s</string>
     <string name="numeric_wday1_md1_wday2_md2">%1$s %2$s/%3$s - %6$s %7$s/%8$s</string>
     <string name="numeric_mdy1_mdy2">%2$s/%3$s/%4$s - %7$s/%8$s/%9$s</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s %2$s/%3$s/%4$s - %6$s %7$s/%8$s/%9$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s/%2$s/%4$s a el %10$s %6$s %8$s/%7$s/%9$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %2$s/%3$s/%4$s a el %10$s %6$s %7$s/%8$s/%9$s</string>
     <string name="numeric_md1_time1_md2_time2">%5$s %2$s/%3$s a el %10$s %7$s/%8$s</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s-%2$s a el %10$s %6$s, %8$s-%7$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s/%3$s a el %10$s %6$s %7$s/%8$s</string>
     <string name="numeric_mdy1_time1_mdy2_time2">%5$s %2$s/%3$s/%4$s a el %10$s %7$s/%8$s/%9$s</string>
     <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s a el %6$s %4$s %5$s</string>
     <string name="wday1_date1_wday2_date2">%1$s %2$s a el %4$s %5$s</string>
@@ -128,18 +128,18 @@
     <string name="wday_date">%2$s %3$s</string>
     <string name="time_wday">%1$s %2$s</string>
     <string name="same_year_md1_md2">%3$s de %2$s a el %8$s de %7$s</string>
-    <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s %2$s a el %6$s %8$s %7$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s de %2$s a el %6$s %8$s de %7$s</string>
     <string name="same_year_md1_time1_md2_time2">%5$s %3$s de %2$s a el %10$s %8$s de %7$s</string>
     <string name="same_month_md1_time1_md2_time2">%5$s %3$s de %2$s a el %10$s %8$s de %7$s</string>
-    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s %2$s a el %10$s %6$s %8$s %7$s</string>
-    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s %2$s a el %10$s %6$s %8$s %7$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s de %2$s a el %10$s %6$s %8$s de %7$s</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s de %2$s a el %10$s %6$s %8$s de %7$s</string>
     <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s de %2$s de %4$s a el %10$s %8$s de %7$s de %9$s</string>
     <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s de %2$s de %4$s a el %10$s %8$s de %7$s de %9$s</string>
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s a el %10$s %6$s, %8$s %7$s %9$s</string>
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s a el %10$s %6$s, %8$s %7$s %9$s</string>
-    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s %4$s a el %6$s, %8$s %7$s %9$s</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s de %2$s de %4$s a el %10$s %6$s %8$s de %7$s de %9$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s de %2$s de %4$s a el %10$s %6$s %8$s de %7$s de %9$s</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s %3$s de %2$s de %4$s a el %6$s %8$s de %7$s de %9$s</string>
     <string name="same_month_md1_md2">%3$s-%8$s de %2$s</string>
-    <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s %2$s a el %6$s %8$s %7$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s de %2$s a el %6$s %8$s de %7$s</string>
     <string name="same_year_mdy1_mdy2">%3$s de %2$s al %8$s de %7$s de %9$s</string>
     <string name="same_month_mdy1_mdy2">%3$s-%8$s de %2$s de %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s de %2$s al %6$s %8$s de %7$s de %9$s</string>
diff --git a/core/res/res/values-fi-rFI/donottranslate-cldr.xml b/core/res/res/values-fi-rFI/donottranslate-cldr.xml
index dd12e57..df3866e 100644
--- a/core/res/res/values-fi-rFI/donottranslate-cldr.xml
+++ b/core/res/res/values-fi-rFI/donottranslate-cldr.xml
@@ -106,7 +106,7 @@
     <string name="time_date">%1$s %3$s</string>
     <string name="abbrev_month_day_year">%-e.%-m.%Y</string>
     <string name="month_day">%-e. %B</string>
-    <string name="month">%-B</string>
+    <string name="month">%-b</string>
     <string name="month_year">%-B %Y</string>
     <string name="abbrev_month_day">%-e. %b</string>
     <string name="abbrev_month">%-b</string>
diff --git a/core/res/res/values-fr-rBE/donottranslate-cldr.xml b/core/res/res/values-fr-rBE/donottranslate-cldr.xml
index ea4ecf2..e190837 100644
--- a/core/res/res/values-fr-rBE/donottranslate-cldr.xml
+++ b/core/res/res/values-fr-rBE/donottranslate-cldr.xml
@@ -109,7 +109,7 @@
     <string name="month">%-B</string>
     <string name="month_year">%B %Y</string>
     <string name="abbrev_month_day">%-e %b</string>
-    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month">%b</string>
     <string name="abbrev_month_year">%b %Y</string>
     <string name="time1_time2">du %1$s au %2$s</string>
     <string name="date1_date2">du %2$s au %5$s</string>
diff --git a/core/res/res/values-fr-rCH/donottranslate-cldr.xml b/core/res/res/values-fr-rCH/donottranslate-cldr.xml
index 0a9835f..48db6b8 100644
--- a/core/res/res/values-fr-rCH/donottranslate-cldr.xml
+++ b/core/res/res/values-fr-rCH/donottranslate-cldr.xml
@@ -109,7 +109,7 @@
     <string name="month">%-B</string>
     <string name="month_year">%B %Y</string>
     <string name="abbrev_month_day">%-e %b</string>
-    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month">%b</string>
     <string name="abbrev_month_year">%b %Y</string>
     <string name="time1_time2">du %1$s au %2$s</string>
     <string name="date1_date2">du %2$s au %5$s</string>
@@ -117,29 +117,29 @@
     <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s - %6$s, %8$s.%7$s</string>
     <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s - %8$s.%7$s.%9$s</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">du %5$s %1$s %3$s/%2$s/%4$s au %10$s %6$s %8$s/%7$s/%9$s</string>
-    <string name="numeric_md1_time1_md2_time2">du %5$s %3$s/%2$s au %10$s %8$s/%7$s</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">du %5$s %1$s %3$s/%2$s au %10$s %6$s %8$s/%7$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">du %5$s %1$s, %3$s.%2$s.%4$s au %10$s %6$s, %8$s.%7$s.%9$s</string>
+    <string name="numeric_md1_time1_md2_time2">du %5$s %3$s.%2$s au %10$s %8$s.%7$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">du %5$s %1$s, %3$s.%2$s au %10$s %6$s, %8$s.%7$s</string>
     <string name="numeric_mdy1_time1_mdy2_time2">du %5$s %3$s.%2$s.%4$s au %10$s %8$s.%7$s.%9$s</string>
-    <string name="wday1_date1_time1_wday2_date2_time2">du %3$s %1$s %2$s au %6$s %4$s %5$s</string>
-    <string name="wday1_date1_wday2_date2">du %1$s %2$s au %4$s %5$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">du %3$s %1$s, %2$s au %6$s %4$s, %5$s</string>
+    <string name="wday1_date1_wday2_date2">du %1$s, %2$s au %4$s, %5$s</string>
     <string name="date1_time1_date2_time2">du %3$s %2$s au %6$s %5$s</string>
-    <string name="time_wday_date">%1$s %2$s %3$s</string>
-    <string name="wday_date">%2$s %3$s</string>
+    <string name="time_wday_date">%1$s %2$s, %3$s</string>
+    <string name="wday_date">%2$s, %3$s</string>
     <string name="time_wday">%1$s %2$s</string>
     <string name="same_year_md1_md2">du %3$s %2$s au %8$s %7$s</string>
-    <string name="same_year_wday1_md1_wday2_md2">du %1$s %3$s %2$s au %6$s %8$s %7$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">du %1$s, %3$s %2$s au %6$s, %8$s %7$s</string>
     <string name="same_year_md1_time1_md2_time2">du %5$s %3$s %2$s au %10$s %8$s %7$s</string>
     <string name="same_month_md1_time1_md2_time2">du %5$s %3$s %2$s au %10$s %8$s %7$s</string>
-    <string name="same_year_wday1_md1_time1_wday2_md2_time2">du %5$s %1$s %3$s %2$s au %10$s %6$s %8$s %7$s</string>
-    <string name="same_month_wday1_md1_time1_wday2_md2_time2">du %5$s %1$s %3$s %2$s au %10$s %6$s %8$s %7$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">du %5$s %1$s, %3$s %2$s au %10$s %6$s, %8$s %7$s</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">du %5$s %1$s, %3$s %2$s au %10$s %6$s, %8$s %7$s</string>
     <string name="same_year_mdy1_time1_mdy2_time2">du %5$s %3$s %2$s %4$s au %10$s %8$s %7$s %9$s</string>
     <string name="same_month_mdy1_time1_mdy2_time2">du %5$s %3$s %2$s %4$s au %10$s %8$s %7$s %9$s</string>
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">du %5$s %1$s %3$s %2$s %4$s au %10$s %6$s %8$s %7$s %9$s</string>
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">du %5$s %1$s %3$s %2$s %4$s au %10$s %6$s %8$s %7$s %9$s</string>
-    <string name="same_month_wday1_mdy1_wday2_mdy2">du %1$s %3$s %2$s %4$s au %6$s %8$s %7$s %9$s</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">du %5$s %1$s, %3$s %2$s %4$s au %10$s %6$s, %8$s %7$s %9$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">du %5$s %1$s, %3$s %2$s %4$s au %10$s %6$s, %8$s %7$s %9$s</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">du %1$s, %3$s %2$s %4$s au %6$s, %8$s %7$s %9$s</string>
     <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
-    <string name="same_month_wday1_md1_wday2_md2">du %1$s %3$s %2$s au %6$s %8$s %7$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">du %1$s, %3$s %2$s au %6$s, %8$s %7$s</string>
     <string name="same_year_mdy1_mdy2">%3$s %2$s au %8$s %7$s %9$s</string>
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s au %6$s, %8$s %7$s %9$s</string>
diff --git a/core/res/res/values-hi-rIN/donottranslate-cldr.xml b/core/res/res/values-hi-rIN/donottranslate-cldr.xml
index 03da515..2a19da4 100644
--- a/core/res/res/values-hi-rIN/donottranslate-cldr.xml
+++ b/core/res/res/values-hi-rIN/donottranslate-cldr.xml
@@ -107,7 +107,7 @@
     <string name="abbrev_month_day_year">%d-%m-%Y</string>
     <string name="month_day">%-e %B</string>
     <string name="month">%-B</string>
-    <string name="month_year">%Y %B</string>
+    <string name="month_year">%B %Y</string>
     <string name="abbrev_month_day">%-e %b</string>
     <string name="abbrev_month">%-b</string>
     <string name="abbrev_month_year">%b %Y</string>
diff --git a/core/res/res/values-hu-rHU/donottranslate-cldr.xml b/core/res/res/values-hu-rHU/donottranslate-cldr.xml
index b56f520..08a70b8 100644
--- a/core/res/res/values-hu-rHU/donottranslate-cldr.xml
+++ b/core/res/res/values-hu-rHU/donottranslate-cldr.xml
@@ -107,17 +107,17 @@
     <string name="abbrev_month_day_year">%Y.%m.%d.</string>
     <string name="month_day">%B %-e.</string>
     <string name="month">%-B</string>
-    <string name="month_year">%Y %B</string>
+    <string name="month_year">%Y. %B</string>
     <string name="abbrev_month_day">%b %-e.</string>
     <string name="abbrev_month">%-b</string>
-    <string name="abbrev_month_year">%Y %b</string>
+    <string name="abbrev_month_year">%Y. %b</string>
     <string name="time1_time2">%1$s - %2$s</string>
     <string name="date1_date2">%2$s - %5$s</string>
     <string name="numeric_md1_md2">%2$s.%3$s. - %7$s.%8$s.</string>
     <string name="numeric_wday1_md1_wday2_md2">%2$s.%3$s., %1$s - %7$s.%8$s., %6$s</string>
     <string name="numeric_mdy1_mdy2">%4$s.%2$s.%3$s. - %9$s.%7$s.%8$s.</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%4$s.%2$s.%3$s., %1$s - %9$s.%7$s.%8$s., %6$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s - %10$s %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %4$s.%2$s.%3$s., %1$s - %10$s %9$s.%7$s.%8$s., %6$s</string>
     <string name="numeric_md1_time1_md2_time2">%5$s %2$s. %3$s. - %10$s %7$s. %8$s.</string>
     <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %2$s. %3$s., %1$s - %10$s %7$s. %8$s., %6$s</string>
     <string name="numeric_mdy1_time1_mdy2_time2">%5$s %4$s.%2$s.%3$s. - %10$s %9$s.%7$s.%8$s.</string>
@@ -128,18 +128,18 @@
     <string name="wday_date">%3$s, %2$s</string>
     <string name="time_wday">%1$s %2$s</string>
     <string name="same_year_md1_md2">%2$s %3$s. - %7$s %8$s.</string>
-    <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%2$s %3$s., %1$s - %7$s %8$s., %6$s</string>
     <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s. - %10$s %7$s %8$s.</string>
     <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s. - %10$s %7$s %8$s.</string>
-    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
-    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %2$s %3$s., %1$s - %10$s %7$s %8$s., %6$s</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %2$s %3$s., %1$s - %10$s %7$s %8$s., %6$s</string>
     <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s. %2$s %3$s. - %10$s %9$s. %7$s %8$s.</string>
     <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s. %2$s %3$s. - %10$s %9$s. %7$s %8$s.</string>
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string>
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string>
-    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s - %6$s, %9$s %7$s %8$s</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %4$s. %2$s %3$s., %1$s - %10$s %9$s. %7$s %8$s., %6$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %4$s. %2$s %3$s., %1$s - %10$s %9$s. %7$s %8$s., %6$s</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">%4$s. %2$s %3$s., %1$s - %9$s. %7$s %8$s., %6$s</string>
     <string name="same_month_md1_md2">%2$s %3$s-%8$s.</string>
-    <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%2$s %3$s., %1$s - %7$s %8$s., %6$s</string>
     <string name="same_year_mdy1_mdy2">%9$s. %2$s %3$s. - %7$s %8$s.</string>
     <string name="same_month_mdy1_mdy2">%9$s. %2$s %3$s-%8$s.</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s. %2$s %3$s., %1$s - %7$s %8$s., %6$s</string>
diff --git a/core/res/res/values-id-rID/donottranslate-cldr.xml b/core/res/res/values-id-rID/donottranslate-cldr.xml
index 22860a7..6adec84 100644
--- a/core/res/res/values-id-rID/donottranslate-cldr.xml
+++ b/core/res/res/values-id-rID/donottranslate-cldr.xml
@@ -107,7 +107,7 @@
     <string name="abbrev_month_day_year">%-e %b %Y</string>
     <string name="month_day">%B %-e</string>
     <string name="month">%-B</string>
-    <string name="month_year">%Y %B</string>
+    <string name="month_year">%B %Y</string>
     <string name="abbrev_month_day">%b %-e</string>
     <string name="abbrev_month">%-b</string>
     <string name="abbrev_month_year">%Y %b</string>
diff --git a/core/res/res/values-it-rCH/donottranslate-cldr.xml b/core/res/res/values-it-rCH/donottranslate-cldr.xml
index 6d9b550..0321edd 100644
--- a/core/res/res/values-it-rCH/donottranslate-cldr.xml
+++ b/core/res/res/values-it-rCH/donottranslate-cldr.xml
@@ -112,29 +112,29 @@
     <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s - %6$s, %8$s.%7$s</string>
     <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s - %8$s.%7$s.%9$s</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s-%2$s-%4$s - %10$s %6$s, %8$s-%7$s-%9$s</string>
-    <string name="numeric_md1_time1_md2_time2">%5$s %3$s/%2$s - %10$s %8$s/%7$s</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s/%2$s - %10$s %6$s %8$s/%7$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s</string>
+    <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s - %10$s %8$s.%7$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s.%2$s - %10$s %6$s, %8$s.%7$s</string>
     <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string>
-    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s - %6$s %4$s %5$s</string>
-    <string name="wday1_date1_wday2_date2">%1$s %2$s - %4$s %5$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
     <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
-    <string name="time_wday_date">%1$s %2$s %3$s</string>
-    <string name="wday_date">%2$s %3$s</string>
+    <string name="time_wday_date">%1$s %2$s, %3$s</string>
+    <string name="wday_date">%2$s, %3$s</string>
     <string name="time_wday">%1$s %2$s</string>
     <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string>
-    <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s %2$s - %6$s, %8$s %7$s</string>
     <string name="same_year_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string>
     <string name="same_month_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string>
-    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s</string>
-    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s %2$s - %10$s %6$s, %8$s %7$s</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s %2$s - %10$s %6$s, %8$s %7$s</string>
     <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string>
     <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string>
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s %2$s %4$s - %10$s %6$s %8$s %7$s %9$s</string>
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s %2$s %4$s - %10$s %6$s %8$s %7$s %9$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>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$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>
     <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
-    <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s %2$s - %6$s, %8$s %7$s</string>
     <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
     <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
diff --git a/core/res/res/values-lt-rLT/donottranslate-cldr.xml b/core/res/res/values-lt-rLT/donottranslate-cldr.xml
index 636a180..20d58e0 100644
--- a/core/res/res/values-lt-rLT/donottranslate-cldr.xml
+++ b/core/res/res/values-lt-rLT/donottranslate-cldr.xml
@@ -108,38 +108,38 @@
     <string name="month_day">%B %-e</string>
     <string name="month">%-B</string>
     <string name="month_year">%Y %B</string>
-    <string name="abbrev_month_day">%b %-e</string>
-    <string name="abbrev_month">%-b</string>
-    <string name="abbrev_month_year">%Y %b</string>
+    <string name="abbrev_month_day">%b %-e d.</string>
+    <string name="abbrev_month">%b</string>
+    <string name="abbrev_month_year">%Y m. %b</string>
     <string name="time1_time2">%1$s - %2$s</string>
     <string name="date1_date2">%2$s - %5$s</string>
     <string name="numeric_md1_md2">%2$s-%3$s - %7$s-%8$s</string>
     <string name="numeric_wday1_md1_wday2_md2">%2$s-%3$s%1$s - %7$s-%8$s%6$s</string>
     <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s - %9$s-%7$s-%8$s</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%4$s-%2$s-%3$s%1$s - %9$s-%7$s-%8$s%6$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s - %10$s %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %4$s-%2$s-%3$s%1$s - %10$s %9$s-%7$s-%8$s%6$s</string>
     <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s - %10$s %7$s-%8$s</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s - %10$s %6$s, %7$s-%8$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %2$s-%3$s%1$s - %10$s %7$s-%8$s%6$s</string>
     <string name="numeric_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s - %10$s %9$s-%7$s-%8$s</string>
-    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s - %6$s %4$s %5$s</string>
-    <string name="wday1_date1_wday2_date2">%1$s %2$s - %4$s %5$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %2$s%1$s - %6$s %5$s%4$s</string>
+    <string name="wday1_date1_wday2_date2">%2$s%1$s - %5$s%4$s</string>
     <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
-    <string name="time_wday_date">%1$s %2$s %3$s</string>
-    <string name="wday_date">%2$s %3$s</string>
+    <string name="time_wday_date">%1$s %3$s%2$s</string>
+    <string name="wday_date">%3$s%2$s</string>
     <string name="time_wday">%1$s %2$s</string>
     <string name="same_year_md1_md2">%2$s %3$s - %7$s %8$s</string>
-    <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%2$s %3$s d.%1$s - %7$s %8$s d.%6$s</string>
     <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s - %10$s %7$s %8$s</string>
     <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s - %10$s %7$s %8$s</string>
-    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
-    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %2$s %3$s d.%1$s - %10$s %7$s %8$s d.%6$s</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %2$s %3$s d.%1$s - %10$s %7$s %8$s d.%6$s</string>
     <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s m. %2$s %3$s d. - %10$s %9$s m. %7$s %8$s d.</string>
     <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s m. %2$s %3$s d. - %10$s %9$s m. %7$s %8$s d.</string>
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string>
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string>
-    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s - %6$s, %9$s %7$s %8$s</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %4$s m. %2$s %3$s d.,%1$s - %10$s %9$s m. %7$s %8$s d.,%6$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %4$s m. %2$s %3$s d.,%1$s - %10$s %9$s m. %7$s %8$s d.,%6$s</string>
+    <string name="same_month_wday1_mdy1_wday2_mdy2">%4$s m. %2$s %3$s d.,%1$s - %9$s m. %7$s %8$s d.,%6$s</string>
     <string name="same_month_md1_md2">%2$s %3$s d.-%8$s d.</string>
-    <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%2$s %3$s d.%1$s - %7$s %8$s d.%6$s</string>
     <string name="same_year_mdy1_mdy2">%9$s m. %2$s %3$s d. - %7$s %8$s d.</string>
     <string name="same_month_mdy1_mdy2">%9$s m. %2$s %3$s d.-%8$s d.</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s m. %2$s %3$s d.,%1$s - %7$s %8$s d.,%6$s</string>
diff --git a/core/res/res/values-nl-rBE/donottranslate-cldr.xml b/core/res/res/values-nl-rBE/donottranslate-cldr.xml
index 5b4cbf7..680a392 100644
--- a/core/res/res/values-nl-rBE/donottranslate-cldr.xml
+++ b/core/res/res/values-nl-rBE/donottranslate-cldr.xml
@@ -117,9 +117,9 @@
     <string name="numeric_wday1_md1_wday2_md2">%1$s %3$s/%2$s - %6$s %8$s/%7$s</string>
     <string name="numeric_mdy1_mdy2">%3$s/%2$s/%4$s - %8$s/%7$s/%9$s</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s %3$s/%2$s/%4$s - %6$s %8$s/%7$s/%9$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s-%2$s-%4$s - %10$s %6$s %8$s-%7$s-%9$s</string>
-    <string name="numeric_md1_time1_md2_time2">%5$s %3$s-%2$s - %10$s %8$s-%7$s</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s-%2$s - %10$s %6$s %8$s-%7$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s/%2$s/%4$s - %10$s %6$s %8$s/%7$s/%9$s</string>
+    <string name="numeric_md1_time1_md2_time2">%5$s %3$s/%2$s - %10$s %8$s/%7$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s/%2$s - %10$s %6$s %8$s/%7$s</string>
     <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s/%2$s/%4$s - %10$s %8$s/%7$s/%9$s</string>
     <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s - %6$s %4$s %5$s</string>
     <string name="wday1_date1_wday2_date2">%1$s %2$s - %4$s %5$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 be0fdb7..f38a2d0 100644
--- a/core/res/res/values-pt-rPT/donottranslate-cldr.xml
+++ b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
@@ -109,7 +109,7 @@
     <string name="month">%-B</string>
     <string name="month_year">%B de %Y</string>
     <string name="abbrev_month_day">%-e de %b</string>
-    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month">%b</string>
     <string name="abbrev_month_year">%b de %Y</string>
     <string name="time1_time2">%1$s - %2$s</string>
     <string name="date1_date2">%2$s - %5$s</string>
diff --git a/core/res/res/values-sk-rSK/donottranslate-cldr.xml b/core/res/res/values-sk-rSK/donottranslate-cldr.xml
index 2b3c6d9..16239df 100644
--- a/core/res/res/values-sk-rSK/donottranslate-cldr.xml
+++ b/core/res/res/values-sk-rSK/donottranslate-cldr.xml
@@ -109,7 +109,7 @@
     <string name="month">%-B</string>
     <string name="month_year">%B %Y</string>
     <string name="abbrev_month_day">%-e. %b</string>
-    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month">%b</string>
     <string name="abbrev_month_year">%b %Y</string>
     <string name="time1_time2">%1$s - %2$s</string>
     <string name="date1_date2">%2$s - %5$s</string>
diff --git a/core/res/res/values-sl-rSI/donottranslate-cldr.xml b/core/res/res/values-sl-rSI/donottranslate-cldr.xml
index 2b2b9c3..b4ea32f 100644
--- a/core/res/res/values-sl-rSI/donottranslate-cldr.xml
+++ b/core/res/res/values-sl-rSI/donottranslate-cldr.xml
@@ -107,39 +107,39 @@
     <string name="abbrev_month_day_year">%-e. %b. %Y</string>
     <string name="month_day">%-e. %B</string>
     <string name="month">%-B</string>
-    <string name="month_year">%Y %B</string>
-    <string name="abbrev_month_day">%b %-e</string>
-    <string name="abbrev_month">%-b</string>
-    <string name="abbrev_month_year">%Y %b</string>
+    <string name="month_year">%B %Y</string>
+    <string name="abbrev_month_day">%-e. %b.</string>
+    <string name="abbrev_month">%b</string>
+    <string name="abbrev_month_year">%b. %Y</string>
     <string name="time1_time2">%1$s – %2$s</string>
     <string name="date1_date2">%2$s – %5$s</string>
     <string name="numeric_md1_md2">%3$s. %2$s. – %8$s. %7$s.</string>
     <string name="numeric_wday1_md1_wday2_md2">%1$s., %3$s. %2$s. – %6$s., %8$s. %7$s.</string>
     <string name="numeric_mdy1_mdy2">%3$s. %2$s. %4$s – %8$s. %7$s. %9$s</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s., %3$s. %2$s. %4$s – %6$s., %8$s. %7$s. %9$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s – %10$s %6$s, %9$s-%7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s., %3$s. %2$s. %4$s – %10$s %6$s., %8$s. %7$s. %9$s</string>
     <string name="numeric_md1_time1_md2_time2">%5$s %3$s. %2$s. – %10$s %8$s. %7$s.</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s – %10$s %6$s, %7$s-%8$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s., %3$s. %2$s. – %10$s %6$s., %8$s. %7$s.</string>
     <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s. %4$s – %10$s %8$s. %7$s. %9$s</string>
-    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s – %6$s %4$s %5$s</string>
-    <string name="wday1_date1_wday2_date2">%1$s %2$s – %4$s %5$s</string>
+    <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s., %2$s – %6$s %4$s., %5$s</string>
+    <string name="wday1_date1_wday2_date2">%1$s., %2$s – %4$s., %5$s</string>
     <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string>
-    <string name="time_wday_date">%1$s %2$s %3$s</string>
-    <string name="wday_date">%2$s %3$s</string>
+    <string name="time_wday_date">%1$s %2$s., %3$s</string>
+    <string name="wday_date">%2$s., %3$s</string>
     <string name="time_wday">%1$s %2$s</string>
     <string name="same_year_md1_md2">%3$s. %2$s – %8$s. %7$s</string>
-    <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+    <string name="same_year_wday1_md1_wday2_md2">%1$s., %3$s. %2$s. – %6$s., %8$s. %7$s.</string>
     <string name="same_year_md1_time1_md2_time2">%5$s %3$s. %2$s – %10$s %8$s. %7$s</string>
     <string name="same_month_md1_time1_md2_time2">%5$s %3$s. %2$s – %10$s %8$s. %7$s</string>
-    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
-    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
+    <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s., %3$s. %2$s. – %10$s %6$s., %8$s. %7$s.</string>
+    <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s., %3$s. %2$s. – %10$s %6$s., %8$s. %7$s.</string>
     <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s. %4$s – %10$s %8$s. %7$s. %9$s</string>
     <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s. %4$s – %10$s %8$s. %7$s. %9$s</string>
-    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string>
-    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string>
-    <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s – %6$s, %9$s %7$s %8$s</string>
+    <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s., %3$s. %2$s. %4$s – %10$s %6$s., %8$s. %7$s. %9$s</string>
+    <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s., %3$s. %2$s. %4$s – %10$s %6$s., %8$s. %7$s. %9$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>
     <string name="same_month_md1_md2">%3$s.–%8$s. %2$s.</string>
-    <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+    <string name="same_month_wday1_md1_wday2_md2">%1$s., %3$s. %2$s. – %6$s., %8$s. %7$s.</string>
     <string name="same_year_mdy1_mdy2">%3$s. %2$s. – %8$s. %7$s. %9$s</string>
     <string name="same_month_mdy1_mdy2">%3$s.–%8$s. %2$s. %9$s</string>
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s., %3$s. %2$s. – %6$s., %8$s. %7$s. %9$s</string>
diff --git a/core/res/res/values-uk-rUA/donottranslate-cldr.xml b/core/res/res/values-uk-rUA/donottranslate-cldr.xml
index 55d3983..c51f8d1 100644
--- a/core/res/res/values-uk-rUA/donottranslate-cldr.xml
+++ b/core/res/res/values-uk-rUA/donottranslate-cldr.xml
@@ -117,9 +117,9 @@
     <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s – %6$s, %8$s.%7$s</string>
     <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s – %8$s.%7$s.%9$s</string>
     <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s – %6$s, %8$s.%7$s.%9$s</string>
-    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s – %10$s %6$s, %9$s-%7$s-%8$s</string>
-    <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s – %10$s %7$s-%8$s</string>
-    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s – %10$s %6$s, %7$s-%8$s</string>
+    <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s.%2$s.%4$s – %10$s %6$s, %8$s.%7$s.%9$s</string>
+    <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s – %10$s %8$s.%7$s</string>
+    <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s.%2$s – %10$s %6$s, %8$s.%7$s</string>
     <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s – %10$s %8$s.%7$s.%9$s</string>
     <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s – %6$s %4$s, %5$s</string>
     <string name="wday1_date1_wday2_date2">%1$s, %2$s – %4$s, %5$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 71178cc8..72ff8b6 100644
--- a/core/res/res/values-vi-rVN/donottranslate-cldr.xml
+++ b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
@@ -109,7 +109,7 @@
     <string name="month">%-B</string>
     <string name="month_year">%B %Y</string>
     <string name="abbrev_month_day">%-e %b</string>
-    <string name="abbrev_month">%-b</string>
+    <string name="abbrev_month">%b</string>
     <string name="abbrev_month_year">%b %Y</string>
     <string name="time1_time2">%1$s - %2$s</string>
     <string name="date1_date2">%2$s - %5$s</string>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 19fde5c..33d550a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -228,6 +228,8 @@
     <string name="httpErrorFileNotFound">The requested file was not found.</string>
     <!-- Displayed when a request failed because there are too many requests right now. -->
     <string name="httpErrorTooManyRequests">Too many requests are being processed. Try again later.</string>
+    <!-- Displayed a toast that a certificate is saved in the keystore -->
+    <string name="certificateSaved">The certificate is saved in the system\'s key store.</string>
 
     <!-- Account notifications --> <skip />
     <!-- A notification is shown when the AccountManager is unable to
@@ -1306,6 +1308,9 @@
     <string name="battery_low_percent_format">less than <xliff:g id="number">%d%%</xliff:g>
     remaining.</string>
 
+    <!-- When the battery is low, this is the label of the button to go to the
+         power usage activity to find out what drained the battery. -->
+    <string name="battery_low_why">Why?</string>
 
     <!-- Title of the alert when something went wrong in the factory test. -->
     <string name="factorytest_failed">Factory test failed</string>
@@ -1333,6 +1338,22 @@
     <!-- 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>
 
+    <!-- Title of an application permission, listed so the user can choose whether
+        they want to allow the application to do this. -->
+    <string name="permlab_readHistoryBookmarks">read Browser\'s history and bookmarks</string>
+    <!-- Description of an application permission, listed so the user can choose whether
+        they want to allow the application to do this. -->
+    <string name="permdesc_readHistoryBookmarks">Allows the application to read all
+        the URLs that the Browser has visited, and all of the Browser\'s bookmarks.</string>
+    <!-- Title of an application permission, listed so the user can choose whether
+        they want to allow the application to do this. -->
+    <string name="permlab_writeHistoryBookmarks">write Browser\'s history and bookmarks</string>
+    <!-- Description of an application permission, listed so the user can choose whether
+        they want to allow the application to do this. -->
+    <string name="permdesc_writeHistoryBookmarks">Allows an application to modify the
+        Browser\'s history or bookmarks stored on your phone. Malicious applications
+        can use this to erase or modify your Browser\'s data.</string>
+
     <!-- 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. Text in the save password dialog, asking if the browser should remember a password. -->
     <string name="save_password_message">Do you want the browser to remember this password?</string>
     <!-- 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. Button in the save password dialog, saying not to remember this password. -->
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index fda584d..e2e93eb 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -16,14 +16,14 @@
 
 package android.graphics;
 
-import android.os.Parcelable;
 import android.os.Parcel;
+import android.os.Parcelable;
 
+import java.io.OutputStream;
 import java.nio.Buffer;
 import java.nio.ByteBuffer;
-import java.nio.ShortBuffer;
 import java.nio.IntBuffer;
-import java.io.OutputStream;
+import java.nio.ShortBuffer;
 
 public final class Bitmap implements Parcelable {
     /**
@@ -32,14 +32,14 @@
      * @see Bitmap#getDensityScale()
      * @see Bitmap#setDensityScale(float)
      *
-     * @hide pending API council approval 
+     * @hide pending API council approval
      */
     public static final float DENSITY_SCALE_UNKNOWN = -1.0f;
 
     // Note:  mNativeBitmap is used by FaceDetector_jni.cpp
     // Don't change/rename without updating FaceDetector_jni.cpp
     private final int mNativeBitmap;
-    
+
     private final boolean mIsMutable;
     private byte[] mNinePatchChunk;   // may be null
     private int mWidth = -1;
@@ -63,7 +63,7 @@
         if (nativeBitmap == 0) {
             throw new RuntimeException("internal error: native bitmap is 0");
         }
-        
+
         // we delete this in our finalizer
         mNativeBitmap = nativeBitmap;
         mIsMutable = isMutable;
@@ -83,7 +83,7 @@
      *
      * @see #setDensityScale(float)
      * @see #isAutoScalingEnabled()
-     * @see #setAutoScalingEnabled(boolean) 
+     * @see #setAutoScalingEnabled(boolean)
      * @see android.util.DisplayMetrics#DEFAULT_DENSITY
      * @see android.util.DisplayMetrics#density
      * @see #DENSITY_SCALE_UNKNOWN
@@ -105,7 +105,7 @@
      *
      * @see #getDensityScale()
      * @see #isAutoScalingEnabled()
-     * @see #setAutoScalingEnabled(boolean) 
+     * @see #setAutoScalingEnabled(boolean)
      * @see android.util.DisplayMetrics#DEFAULT_DENSITY
      * @see android.util.DisplayMetrics#density
      * @see #DENSITY_SCALE_UNKNOWN
@@ -126,7 +126,7 @@
      * <p>Auto scaling is turned off by default. If auto scaling is enabled but the
      * bitmap has an unknown density scale, then the bitmap will never be automatically
      * scaled at drawing time.</p>
-     * 
+     *
      * @return True if the bitmap must be scaled at drawing time, false otherwise.
      *
      * @see #setAutoScalingEnabled(boolean)
@@ -167,7 +167,7 @@
     public void setNinePatchChunk(byte[] chunk) {
         mNinePatchChunk = chunk;
     }
-    
+
     /**
      * Free up the memory associated with this bitmap's pixels, and mark the
      * bitmap as "dead", meaning it will throw an exception if getPixels() or
@@ -194,7 +194,7 @@
     public final boolean isRecycled() {
         return mRecycled;
     }
-    
+
     /**
      * This is called by methods that want to throw an exception if the bitmap
      * has already been recycled.
@@ -204,7 +204,7 @@
             throw new IllegalStateException(errorMessage);
         }
     }
-    
+
     /**
      * Common code for checking that x and y are >= 0
      *
@@ -246,16 +246,16 @@
             this.nativeInt = ni;
         }
         final int nativeInt;
-        
+
         /* package */ static Config nativeToConfig(int ni) {
             return sConfigs[ni];
         }
-        
+
         private static Config sConfigs[] = {
             null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
         };
     }
-    
+
     /**
      * Copy the bitmap's pixels into the specified buffer (allocated by the
      * caller). An exception is thrown if the buffer is not large enough to
@@ -275,16 +275,16 @@
         } else {
             throw new RuntimeException("unsupported Buffer subclass");
         }
-        
+
         long bufferSize = (long)elements << shift;
         long pixelSize = (long)getRowBytes() * getHeight();
-        
+
         if (bufferSize < pixelSize) {
             throw new RuntimeException("Buffer not large enough for pixels");
         }
-        
+
         nativeCopyPixelsToBuffer(mNativeBitmap, dst);
-        
+
         // now update the buffer's position
         int position = dst.position();
         position += pixelSize >> shift;
@@ -299,7 +299,7 @@
      */
     public void copyPixelsFromBuffer(Buffer src) {
         checkRecycled("copyPixelsFromBuffer called on recycled bitmap");
-        
+
         int elements = src.remaining();
         int shift;
         if (src instanceof ByteBuffer) {
@@ -311,17 +311,17 @@
         } else {
             throw new RuntimeException("unsupported Buffer subclass");
         }
-        
+
         long bufferBytes = (long)elements << shift;
         long bitmapBytes = (long)getRowBytes() * getHeight();
-        
+
         if (bufferBytes < bitmapBytes) {
             throw new RuntimeException("Buffer not large enough for pixels");
         }
-        
+
         nativeCopyPixelsFromBuffer(mNativeBitmap, src);
     }
-        
+
     /**
      * Tries to make a new bitmap based on the dimensions of this bitmap,
      * setting the new bitmap's config to the one specified, and then copying
@@ -350,7 +350,7 @@
         if (m == null) {
             m = new Matrix();
         }
-        
+
         final int width = src.getWidth();
         final int height = src.getHeight();
         final float sx = dstWidth  / (float)width;
@@ -365,9 +365,9 @@
             }
         }
 
-        return b; 
+        return b;
     }
-    
+
     /**
      * Returns an immutable bitmap from the source bitmap. The new bitmap may
      * be the same object as source, or a copy may have been made.
@@ -390,7 +390,7 @@
     public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) {
         return createBitmap(source, x, y, width, height, null, false);
     }
-    
+
     /**
      * Returns an immutable bitmap from subset of the source bitmap,
      * transformed by the optional matrix.
@@ -425,7 +425,7 @@
                 height == source.getHeight() && (m == null || m.isIdentity())) {
             return source;
         }
-        
+
         int neww = width;
         int newh = height;
         Canvas canvas = new Canvas();
@@ -470,7 +470,7 @@
 
         return bitmap;
     }
-    
+
     /**
      * Returns a mutable bitmap with the specified width and height.
      *
@@ -484,7 +484,7 @@
         bm.eraseColor(0);    // start with black/transparent pixels
         return bm;
     }
-    
+
     /**
      * Returns a immutable bitmap with the specified width and height, with each
      * pixel value set to the corresponding value in the colors array.
@@ -593,7 +593,7 @@
         return nativeCompress(mNativeBitmap, format.nativeInt, quality,
                               stream, new byte[WORKING_COMPRESS_STORAGE]);
     }
-    
+
     /**
      * Returns true if the bitmap is marked as mutable (i.e. can be drawn into)
      */
@@ -610,7 +610,7 @@
     public final int getHeight() {
         return mHeight == -1 ? mHeight = nativeHeight(mNativeBitmap) : mHeight;
     }
-    
+
     /**
      * Convenience method that returns the width of this bitmap divided
      * by the density scale factor.
@@ -648,7 +648,7 @@
     public final int getRowBytes() {
         return nativeRowBytes(mNativeBitmap);
     }
-    
+
     /**
      * If the bitmap's internal config is in one of the public formats, return
      * that config, otherwise return null.
@@ -690,7 +690,7 @@
         checkPixelAccess(x, y);
         return nativeGetPixel(mNativeBitmap, x, y);
     }
-    
+
     /**
      * Returns in pixels[] a copy of the data in the bitmap. Each value is
      * a packed int representing a {@link Color}. The stride parameter allows
@@ -722,7 +722,7 @@
         nativeGetPixels(mNativeBitmap, pixels, offset, stride,
                         x, y, width, height);
     }
-    
+
     /**
      * Shared code to check for illegal arguments passed to getPixel()
      * or setPixel()
@@ -779,7 +779,7 @@
             throw new ArrayIndexOutOfBoundsException();
         }
     }
-    
+
     /**
      * Write the specified {@link Color} into the bitmap (assuming it is
      * mutable) at the x,y coordinate.
@@ -799,10 +799,10 @@
         checkPixelAccess(x, y);
         nativeSetPixel(mNativeBitmap, x, y, color);
     }
-    
+
     /**
      * Replace pixels in the bitmap with the colors in the array. Each element
-     * in the array is a packed int prepresenting a {@link Color} 
+     * in the array is a packed int prepresenting a {@link Color}
      *
      * @param pixels   The colors to write to the bitmap
      * @param offset   The index of the first color to read from pixels[]
@@ -834,7 +834,7 @@
         nativeSetPixels(mNativeBitmap, pixels, offset, stride,
                         x, y, width, height);
     }
-    
+
     public static final Parcelable.Creator<Bitmap> CREATOR
             = new Parcelable.Creator<Bitmap>() {
         /**
@@ -884,7 +884,7 @@
     public Bitmap extractAlpha() {
         return extractAlpha(null, null);
     }
-    
+
     /**
      * Returns a new bitmap that captures the alpha values of the original.
      * These values may be affected by the optional Paint parameter, which
@@ -917,6 +917,22 @@
         return bm;
     }
 
+    /**
+     * Rebuilds any caches associated with the bitmap that are used for
+     * drawing it. In the case of purgeable bitmaps, this call will attempt to
+     * ensure that the pixels have been decoded.
+     * If this is called on more than one bitmap in sequence, the priority is
+     * given in LRU order (i.e. the last bitmap called will be given highest
+     * priority).
+     *
+     * For bitmaps with no associated caches, this call is effectively a no-op,
+     * and therefore is harmless.
+     */
+    public void prepareToDraw() {
+        nativePrepareToDraw(mNativeBitmap);
+    }
+
+    @Override
     protected void finalize() throws Throwable {
         try {
             nativeDestructor(mNativeBitmap);
@@ -924,7 +940,7 @@
             super.finalize();
         }
     }
-    
+
     //////////// native methods
 
     private static native Bitmap nativeCreate(int[] colors, int offset,
@@ -944,12 +960,12 @@
     private static native int nativeRowBytes(int nativeBitmap);
     private static native int nativeConfig(int nativeBitmap);
     private static native boolean nativeHasAlpha(int nativeBitmap);
-    
+
     private static native int nativeGetPixel(int nativeBitmap, int x, int y);
     private static native void nativeGetPixels(int nativeBitmap, int[] pixels,
                                                int offset, int stride, int x,
                                                int y, int width, int height);
-    
+
     private static native void nativeSetPixel(int nativeBitmap, int x, int y,
                                               int color);
     private static native void nativeSetPixels(int nativeBitmap, int[] colors,
@@ -969,6 +985,8 @@
                                                     int nativePaint,
                                                     int[] offsetXY);
 
+    private static native void nativePrepareToDraw(int nativeBitmap);
+
     /* package */ final int ni() {
         return mNativeBitmap;
     }
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 06d53e3..4498e1a 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1404,7 +1404,11 @@
     
     protected void finalize() throws Throwable {
         super.finalize();
-        finalizer(mNativeCanvas);
+        // If the constructor threw an exception before setting mNativeCanvas, the native finalizer
+        // must not be invoked.
+        if (mNativeCanvas != 0) {
+            finalizer(mNativeCanvas);
+        }
     }
 
     /**
diff --git a/include/utils/BackupHelpers.h b/include/utils/BackupHelpers.h
index fa7f8d5..a21359f 100644
--- a/include/utils/BackupHelpers.h
+++ b/include/utils/BackupHelpers.h
@@ -19,6 +19,7 @@
 
 #include <utils/Errors.h>
 #include <utils/String8.h>
+#include <utils/KeyedVector.h>
 
 namespace android {
 
@@ -32,6 +33,27 @@
     int dataSize; // size of the data, not including the padding, -1 means delete
 } entity_header_v1;
 
+struct SnapshotHeader {
+    int magic0;
+    int fileCount;
+    int magic1;
+    int totalSize;
+};
+
+struct FileState {
+    int modTime_sec;
+    int modTime_nsec;
+    int size;
+    int crc32;
+    int nameLen;
+};
+
+struct FileRec {
+    String8 file;
+    bool deleted;
+    FileState s;
+};
+
 
 /**
  * Writes the data.
@@ -49,6 +71,8 @@
     status_t WriteEntityHeader(const String8& key, size_t dataSize);
     status_t WriteEntityData(const void* data, size_t size);
 
+    void SetKeyPrefix(const String8& keyPrefix);
+
 private:
     explicit BackupDataWriter();
     status_t write_padding_for(int n);
@@ -57,6 +81,7 @@
     status_t m_status;
     ssize_t m_pos;
     int m_entityCount;
+    String8 m_keyPrefix;
 };
 
 /**
@@ -94,11 +119,25 @@
         int type;
         entity_header_v1 entity;
     } m_header;
+    String8 m_key;
 };
 
 int back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
         char const* const* files, char const* const *keys, int fileCount);
 
+class RestoreHelperBase
+{
+public:
+    RestoreHelperBase();
+    ~RestoreHelperBase();
+
+    status_t WriteFile(const String8& filename, BackupDataReader* in);
+    status_t WriteSnapshot(int fd);
+
+private:
+    void* m_buf;
+    KeyedVector<String8,FileRec> m_files;
+};
 
 #define TEST_BACKUP_HELPERS 1
 
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 9b8c302..f1029b7 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -71,7 +71,7 @@
  * The relative sizes of the stretchy segments indicates the relative
  * amount of stretchiness of the regions bordered by the segments.  For
  * example, regions 3, 7 and 11 above will take up more horizontal space
- * than regions 1, 5 and 9 since the horizonal segment associated with
+ * than regions 1, 5 and 9 since the horizontal segment associated with
  * the first set of regions is larger than the other set of regions.  The
  * ratios of the amount of horizontal (or vertical) space taken by any
  * two stretchable slices is exactly the ratio of their corresponding
@@ -87,7 +87,7 @@
  * the leftmost slices always start at x=0 and the rightmost slices
  * always end at the end of the image. So, for example, the regions 0,
  * 4 and 8 (which are fixed along the X axis) start at x value 0 and
- * go to xDiv[0] amd slices 2, 6 and 10 start at xDiv[1] and end at
+ * go to xDiv[0] and slices 2, 6 and 10 start at xDiv[1] and end at
  * xDiv[2].
  *
  * The array pointed to by the colors field lists contains hints for
@@ -626,25 +626,25 @@
     event_code_t next();
 
     // These are available for all nodes:
-    const int32_t getCommentID() const;
+    int32_t getCommentID() const;
     const uint16_t* getComment(size_t* outLen) const;
-    const uint32_t getLineNumber() const;
+    uint32_t getLineNumber() const;
     
     // This is available for TEXT:
-    const int32_t getTextID() const;
+    int32_t getTextID() const;
     const uint16_t* getText(size_t* outLen) const;
     ssize_t getTextValue(Res_value* outValue) const;
     
     // These are available for START_NAMESPACE and END_NAMESPACE:
-    const int32_t getNamespacePrefixID() const;
+    int32_t getNamespacePrefixID() const;
     const uint16_t* getNamespacePrefix(size_t* outLen) const;
-    const int32_t getNamespaceUriID() const;
+    int32_t getNamespaceUriID() const;
     const uint16_t* getNamespaceUri(size_t* outLen) const;
     
     // These are available for START_TAG and END_TAG:
-    const int32_t getElementNamespaceID() const;
+    int32_t getElementNamespaceID() const;
     const uint16_t* getElementNamespace(size_t* outLen) const;
-    const int32_t getElementNameID() const;
+    int32_t getElementNameID() const;
     const uint16_t* getElementName(size_t* outLen) const;
     
     // Remaining methods are for retrieving information about attributes
@@ -653,14 +653,14 @@
     size_t getAttributeCount() const;
     
     // Returns -1 if no namespace, -2 if idx out of range.
-    const int32_t getAttributeNamespaceID(size_t idx) const;
+    int32_t getAttributeNamespaceID(size_t idx) const;
     const uint16_t* getAttributeNamespace(size_t idx, size_t* outLen) const;
     
-    const int32_t getAttributeNameID(size_t idx) const;
+    int32_t getAttributeNameID(size_t idx) const;
     const uint16_t* getAttributeName(size_t idx, size_t* outLen) const;
-    const uint32_t getAttributeNameResID(size_t idx) const;
+    uint32_t getAttributeNameResID(size_t idx) const;
     
-    const int32_t getAttributeValueStringID(size_t idx) const;
+    int32_t getAttributeValueStringID(size_t idx) const;
     const uint16_t* getAttributeStringValue(size_t idx, size_t* outLen) const;
     
     int32_t getAttributeDataType(size_t idx) const;
@@ -1781,7 +1781,7 @@
     void getLocales(Vector<String8>* locales) const;
 
 #ifndef HAVE_ANDROID_OS
-    void print() const;
+    void print(bool inclValues) const;
 #endif
 
 private:
diff --git a/keystore/java/android/security/Keystore.java b/keystore/java/android/security/Keystore.java
index ce3fa88..2a3e6a7 100644
--- a/keystore/java/android/security/Keystore.java
+++ b/keystore/java/android/security/Keystore.java
@@ -88,7 +88,7 @@
     public abstract String generateKeyPair(
             int keyStrengthIndex, String challenge, String organizations);
 
-    public abstract void addCertificate(String cert);
+    public abstract void addCertificate(byte[] cert);
 
     private static class FileKeystore extends Keystore {
         private static final String SERVICE_NAME = "keystore";
@@ -217,7 +217,7 @@
         }
 
         @Override
-        public void addCertificate(String cert) {
+        public void addCertificate(byte[] cert) {
             // TODO: real implementation
         }
 
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index f14d7e9..eec645e 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -189,9 +189,14 @@
     
     
     char property[PROPERTY_VALUE_MAX];
-    if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
-        LOGW("ro.sf.lcd_density not defined, using 160 dpi by default.");
-        strcpy(property, "160");
+    /* Read density from build-specific ro.sf.lcd_density property
+     * except if it is overriden by qemu.sf.lcd_density.
+     */
+    if (property_get("qemu.sf.lcd_density", property, NULL) <= 0) {
+        if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
+            LOGW("ro.sf.lcd_density not defined, using 160 dpi by default.");
+            strcpy(property, "160");
+        }
     }
     mDensity = atoi(property) * (1.0f/160.0f);
 
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index 34b37ed..0868cff 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -99,10 +99,20 @@
         return amt;
     }
 
+    String8 k;
+    if (m_keyPrefix.length() > 0) {
+        k = m_keyPrefix;
+        k += ":";
+        k += key;
+    } else {
+        k = key;
+    }
+    LOGD("m_keyPrefix=%s key=%s k=%s", m_keyPrefix.string(), key.string(), k.string());
+
     entity_header_v1 header;
     ssize_t keyLen;
 
-    keyLen = key.length();
+    keyLen = k.length();
 
     header.type = tolel(BACKUP_HEADER_ENTITY_V1);
     header.keyLen = tolel(keyLen);
@@ -115,7 +125,7 @@
     }
     m_pos += amt;
 
-    amt = write(m_fd, key.string(), keyLen+1);
+    amt = write(m_fd, k.string(), keyLen+1);
     if (amt != keyLen+1) {
         m_status = errno;
         return m_status;
@@ -148,6 +158,11 @@
     return NO_ERROR;
 }
 
+void
+BackupDataWriter::SetKeyPrefix(const String8& keyPrefix)
+{
+    m_keyPrefix = keyPrefix;
+}
 
 
 BackupDataReader::BackupDataReader(int fd)
@@ -205,12 +220,17 @@
     amt = read(m_fd, &m_header, sizeof(m_header));
     *done = m_done = (amt == 0);
     CHECK_SIZE(amt, sizeof(m_header));
+    m_pos += sizeof(m_header);
+    if (type) {
+        *type = m_header.type;
+    }
 
     // validate and fix up the fields.
     m_header.type = fromlel(m_header.type);
     switch (m_header.type)
     {
         case BACKUP_HEADER_ENTITY_V1:
+        {
             m_header.entity.keyLen = fromlel(m_header.entity.keyLen);
             if (m_header.entity.keyLen <= 0) {
                 LOGD("Entity header at %d has keyLen<=0: 0x%08x\n", (int)m_pos,
@@ -219,15 +239,27 @@
             }
             m_header.entity.dataSize = fromlel(m_header.entity.dataSize);
             m_entityCount++;
+
+            // read the rest of the header (filename)
+            size_t size = m_header.entity.keyLen;
+            char* buf = m_key.lockBuffer(size);
+            if (buf == NULL) {
+                m_status = ENOMEM;
+                return m_status;
+            }
+            int amt = read(m_fd, buf, size+1);
+            CHECK_SIZE(amt, (int)size+1);
+            m_key.unlockBuffer(size);
+            m_pos += size+1;
+            SKIP_PADDING();
+            m_dataEndPos = m_pos + m_header.entity.dataSize;
+
             break;
+        }
         default:
             LOGD("Chunk header at %d has invalid type: 0x%08x", (int)m_pos, (int)m_header.type);
             m_status = EINVAL;
     }
-    m_pos += sizeof(m_header);
-    if (type) {
-        *type = m_header.type;
-    }
     
     return m_status;
 }
@@ -247,20 +279,8 @@
     if (m_header.type != BACKUP_HEADER_ENTITY_V1) {
         return EINVAL;
     }
-    size_t size = m_header.entity.keyLen;
-    char* buf = key->lockBuffer(size);
-    if (key == NULL) {
-        key->unlockBuffer();
-        m_status = ENOMEM;
-        return m_status;
-    }
-    int amt = read(m_fd, buf, size+1);
-    CHECK_SIZE(amt, (int)size+1);
-    key->unlockBuffer(size);
-    m_pos += size+1;
+    *key = m_key;
     *dataSize = m_header.entity.dataSize;
-    SKIP_PADDING();
-    m_dataEndPos = m_pos + *dataSize;
     return NO_ERROR;
 }
 
@@ -285,20 +305,24 @@
 BackupDataReader::ReadEntityData(void* data, size_t size)
 {
     if (m_status != NO_ERROR) {
-        return m_status;
+        return -1;
     }
     int remaining = m_dataEndPos - m_pos;
     //LOGD("ReadEntityData size=%d m_pos=0x%x m_dataEndPos=0x%x remaining=%d\n",
     //        size, m_pos, m_dataEndPos, remaining);
-    if (size > remaining) {
-        size = remaining;
-    }
     if (remaining <= 0) {
         return 0;
     }
+    if (((int)size) > remaining) {
+        size = remaining;
+    }
+    //LOGD("   reading %d bytes", size);
     int amt = read(m_fd, data, size);
-    CHECK_SIZE(amt, (int)size);
-    m_pos += size;
+    if (amt < 0) {
+        m_status = errno;
+        return -1;
+    }
+    m_pos += amt;
     return amt;
 }
 
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index c1d5404..d65a457 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -47,27 +47,6 @@
 #define LOGP(x...) LOGD(x)
 #endif
 
-struct SnapshotHeader {
-    int magic0;
-    int fileCount;
-    int magic1;
-    int totalSize;
-};
-
-struct FileState {
-    int modTime_sec;
-    int modTime_nsec;
-    int size;
-    int crc32;
-    int nameLen;
-};
-
-struct FileRec {
-    char const* file; // this object does not own this string
-    bool deleted;
-    FileState s;
-};
-
 const static int ROUND_UP[4] = { 0, 3, 2, 1 };
 
 static inline int
@@ -310,7 +289,8 @@
     for (int i=0; i<fileCount; i++) {
         String8 key(keys[i]);
         FileRec r;
-        char const* file = r.file = files[i];
+        char const* file = files[i];
+        r.file = file;
         struct stat st;
 
         err = stat(file, &st);
@@ -351,20 +331,20 @@
         }
         else if (cmp > 0) {
             // file added
-            LOGP("file added: %s", g.file);
-            write_update_file(dataStream, q, g.file);
+            LOGP("file added: %s", g.file.string());
+            write_update_file(dataStream, q, g.file.string());
             m++;
         }
         else {
             // both files exist, check them
             const FileState& f = oldSnapshot.valueAt(n);
 
-            int fd = open(g.file, O_RDONLY);
+            int fd = open(g.file.string(), O_RDONLY);
             if (fd < 0) {
                 // We can't open the file.  Don't report it as a delete either.  Let the
                 // server keep the old version.  Maybe they'll be able to deal with it
                 // on restore.
-                LOGP("Unable to open file %s - skipping", g.file);
+                LOGP("Unable to open file %s - skipping", g.file.string());
             } else {
                 g.s.crc32 = compute_crc32(fd);
 
@@ -375,7 +355,7 @@
                         g.s.modTime_sec, g.s.modTime_nsec, g.s.size, g.s.crc32);
                 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
                         || f.size != g.s.size || f.crc32 != g.s.crc32) {
-                    write_update_file(dataStream, fd, p, g.file);
+                    write_update_file(dataStream, fd, p, g.file.string());
                 }
 
                 close(fd);
@@ -395,7 +375,7 @@
     while (m<fileCount) {
         const String8& q = newSnapshot.keyAt(m);
         FileRec& g = newSnapshot.editValueAt(m);
-        write_update_file(dataStream, q, g.file);
+        write_update_file(dataStream, q, g.file.string());
         m++;
     }
 
@@ -404,6 +384,86 @@
     return 0;
 }
 
+#define RESTORE_BUF_SIZE (8*1024)
+
+RestoreHelperBase::RestoreHelperBase()
+{
+    m_buf = malloc(RESTORE_BUF_SIZE);
+}
+
+RestoreHelperBase::~RestoreHelperBase()
+{
+    free(m_buf);
+}
+
+status_t
+RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
+{
+    ssize_t err;
+    size_t dataSize;
+    String8 key;
+    int fd;
+    void* buf = m_buf;
+    ssize_t amt;
+    int mode;
+    int crc;
+    struct stat st;
+    FileRec r;
+
+    err = in->ReadEntityHeader(&key, &dataSize);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    // TODO: World readable/writable for now.
+    mode = 0666;
+
+    // Write the file and compute the crc
+    crc = crc32(0L, Z_NULL, 0);
+    fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
+    if (fd == -1) {
+        LOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
+        return errno;
+    }
+    
+    while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
+        err = write(fd, buf, amt);
+        if (err != amt) {
+            close(fd);
+            LOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
+            return errno;
+        }
+        crc = crc32(crc, (Bytef*)buf, amt);
+    }
+
+    close(fd);
+
+    // Record for the snapshot
+    err = stat(filename.string(), &st);
+    if (err != 0) {
+        LOGW("Error stating file that we just created %s", filename.string());
+        return errno;
+    }
+
+    r.file = filename;
+    r.deleted = false;
+    r.s.modTime_sec = st.st_mtime;
+    r.s.modTime_nsec = 0; // workaround sim breakage
+    //r.s.modTime_nsec = st.st_mtime_nsec;
+    r.s.size = st.st_size;
+    r.s.crc32 = crc;
+
+    m_files.add(key, r);
+
+    return NO_ERROR;
+}
+
+status_t
+RestoreHelperBase::WriteSnapshot(int fd)
+{
+    return write_snapshot_file(fd, m_files);;
+}
+
 #if TEST_BACKUP_HELPERS
 
 #define SCRATCH_DIR "/data/backup_helper_test/"
@@ -560,7 +620,6 @@
     FileState states[4];
     FileRec r;
     r.deleted = false;
-    r.file = NULL;
 
     states[0].modTime_sec = 0xfedcba98;
     states[0].modTime_nsec = 0xdeadbeef;
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 3d12dca..e4f9f0f 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -544,7 +544,7 @@
     return mEventCode;
 }
 
-const int32_t ResXMLParser::getCommentID() const
+int32_t ResXMLParser::getCommentID() const
 {
     return mCurNode != NULL ? dtohl(mCurNode->comment.index) : -1;
 }
@@ -555,12 +555,12 @@
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
-const uint32_t ResXMLParser::getLineNumber() const
+uint32_t ResXMLParser::getLineNumber() const
 {
     return mCurNode != NULL ? dtohl(mCurNode->lineNumber) : -1;
 }
 
-const int32_t ResXMLParser::getTextID() const
+int32_t ResXMLParser::getTextID() const
 {
     if (mEventCode == TEXT) {
         return dtohl(((const ResXMLTree_cdataExt*)mCurExt)->data.index);
@@ -583,7 +583,7 @@
     return BAD_TYPE;
 }
 
-const int32_t ResXMLParser::getNamespacePrefixID() const
+int32_t ResXMLParser::getNamespacePrefixID() const
 {
     if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
         return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->prefix.index);
@@ -598,7 +598,7 @@
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
-const int32_t ResXMLParser::getNamespaceUriID() const
+int32_t ResXMLParser::getNamespaceUriID() const
 {
     if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
         return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->uri.index);
@@ -613,7 +613,7 @@
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
-const int32_t ResXMLParser::getElementNamespaceID() const
+int32_t ResXMLParser::getElementNamespaceID() const
 {
     if (mEventCode == START_TAG) {
         return dtohl(((const ResXMLTree_attrExt*)mCurExt)->ns.index);
@@ -630,7 +630,7 @@
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
-const int32_t ResXMLParser::getElementNameID() const
+int32_t ResXMLParser::getElementNameID() const
 {
     if (mEventCode == START_TAG) {
         return dtohl(((const ResXMLTree_attrExt*)mCurExt)->name.index);
@@ -655,7 +655,7 @@
     return 0;
 }
 
-const int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const
+int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const
 {
     if (mEventCode == START_TAG) {
         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
@@ -678,7 +678,7 @@
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
-const int32_t ResXMLParser::getAttributeNameID(size_t idx) const
+int32_t ResXMLParser::getAttributeNameID(size_t idx) const
 {
     if (mEventCode == START_TAG) {
         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
@@ -701,7 +701,7 @@
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
-const uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
+uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
 {
     int32_t id = getAttributeNameID(idx);
     if (id >= 0 && (size_t)id < mTree.mNumResIds) {
@@ -710,7 +710,7 @@
     return 0;
 }
 
-const int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const
+int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const
 {
     if (mEventCode == START_TAG) {
         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
@@ -3830,9 +3830,45 @@
 #define CHAR16_ARRAY_EQ(constant, var, len) \
         ((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len))))
 
-void ResTable::print() const
+void print_complex(uint32_t complex, bool isFraction)
 {
-    printf("mError=0x%x (%s)\n", mError, strerror(mError));
+    const float MANTISSA_MULT =
+        1.0f / (1<<Res_value::COMPLEX_MANTISSA_SHIFT);
+    const float RADIX_MULTS[] = {
+        1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT,
+        1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT
+    };
+
+    float value = (complex&(Res_value::COMPLEX_MANTISSA_MASK
+                   <<Res_value::COMPLEX_MANTISSA_SHIFT))
+            * RADIX_MULTS[(complex>>Res_value::COMPLEX_RADIX_SHIFT)
+                            & Res_value::COMPLEX_RADIX_MASK];
+    printf("%f", value);
+    
+    if (isFraction) {
+        switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
+            case Res_value::COMPLEX_UNIT_PX: printf("px"); break;
+            case Res_value::COMPLEX_UNIT_DIP: printf("dp"); break;
+            case Res_value::COMPLEX_UNIT_SP: printf("sp"); break;
+            case Res_value::COMPLEX_UNIT_PT: printf("pt"); break;
+            case Res_value::COMPLEX_UNIT_IN: printf("in"); break;
+            case Res_value::COMPLEX_UNIT_MM: printf("mm"); break;
+            default: printf(" (unknown unit)"); break;
+        }
+    } else {
+        switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
+            case Res_value::COMPLEX_UNIT_FRACTION: printf("%%"); break;
+            case Res_value::COMPLEX_UNIT_FRACTION_PARENT: printf("%%p"); break;
+            default: printf(" (unknown unit)"); break;
+        }
+    }
+}
+
+void ResTable::print(bool inclValues) const
+{
+    if (mError != 0) {
+        printf("mError=0x%x (%s)\n", mError, strerror(mError));
+    }
 #if 0
     printf("mParams=%c%c-%c%c,\n",
             mParams.language[0], mParams.language[1],
@@ -3947,6 +3983,8 @@
                                  (void*)(entriesStart + thisOffset));
                             continue;
                         }
+                        
+                        const Res_value* value = NULL;
                         if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) {
                             printf("<bag>");
                         } else {
@@ -3962,7 +4000,7 @@
                                 continue;
                             }
                             
-                            const Res_value* value = (const Res_value*)
+                            value = (const Res_value*)
                                 (((const uint8_t*)ent) + esize);
                             printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
                                    (int)value->dataType, (int)dtohl(value->data),
@@ -3973,6 +4011,49 @@
                             printf(" (PUBLIC)");
                         }
                         printf("\n");
+                        
+                        if (inclValues) {
+                            if (value != NULL) {
+                                printf("          ");
+                                if (value->dataType == Res_value::TYPE_NULL) {
+                                    printf("(null)\n");
+                                } else if (value->dataType == Res_value::TYPE_REFERENCE) {
+                                    printf("(reference) 0x%08x\n", value->data);
+                                } else if (value->dataType == Res_value::TYPE_ATTRIBUTE) {
+                                    printf("(attribute) 0x%08x\n", value->data);
+                                } else if (value->dataType == Res_value::TYPE_STRING) {
+                                    size_t len;
+                                    const char16_t* str = pkg->header->values.stringAt(
+                                            value->data, &len);
+                                    if (str == NULL) {
+                                        printf("(string) null\n");
+                                    } else {
+                                        printf("(string) \"%s\"\n",
+                                                String8(str, len).string());
+                                    } 
+                                } else if (value->dataType == Res_value::TYPE_FLOAT) {
+                                    printf("(float) %g\n", *(const float*)&value->data);
+                                } else if (value->dataType == Res_value::TYPE_DIMENSION) {
+                                    printf("(dimension) ");
+                                    print_complex(value->data, false);
+                                    printf("\n");
+                                } else if (value->dataType == Res_value::TYPE_FRACTION) {
+                                    printf("(fraction) ");
+                                    print_complex(value->data, true);
+                                    printf("\n");
+                                } else if (value->dataType >= Res_value::TYPE_FIRST_COLOR_INT
+                                        || value->dataType <= Res_value::TYPE_LAST_COLOR_INT) {
+                                    printf("(color) #%08x\n", value->data);
+                                } else if (value->dataType == Res_value::TYPE_INT_BOOLEAN) {
+                                    printf("(boolean) %s\n", value->data ? "true" : "false");
+                                } else if (value->dataType >= Res_value::TYPE_FIRST_INT
+                                        || value->dataType <= Res_value::TYPE_LAST_INT) {
+                                    printf("(int) 0x%08x or %d\n", value->data, value->data);
+                                } else {
+                                    printf("(unknown type)\n");
+                                }
+                            }
+                        }
                     }
                 }
             }
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
old mode 100644
new mode 100755
index 9698553..5c8fcf2
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -208,12 +208,6 @@
     private GpsNetworkThread mNetworkThread;
     private Object mNetworkThreadLock = new Object();
 
-    private String mSuplHost;
-    private int mSuplPort;
-    private String mC2KHost;
-    private int mC2KPort;
-    private boolean mSetSuplServer;
-    private boolean mSetC2KServer;
     private String mAGpsApn;
     private int mAGpsDataConnectionState;
     private final ConnectivityManager mConnMgr;
@@ -355,23 +349,27 @@
             stream.close();
             mNtpServer = mProperties.getProperty("NTP_SERVER", null);
 
-            mSuplHost = mProperties.getProperty("SUPL_HOST");
+            String host = mProperties.getProperty("SUPL_HOST");
             String portString = mProperties.getProperty("SUPL_PORT");
-            if (mSuplHost != null && portString != null) {
+            if (host != null && portString != null) {
                 try {
-                    mSuplPort = Integer.parseInt(portString);
-                    mSetSuplServer = true;
+                    int port = Integer.parseInt(portString);
+                    native_set_agps_server(AGPS_TYPE_SUPL, host, port);
+                    // use MS-Based position mode if SUPL support is enabled
+                    mPositionMode = GPS_POSITION_MODE_MS_BASED;
                 } catch (NumberFormatException e) {
                     Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
                 }
             }
 
-            mC2KHost = mProperties.getProperty("C2K_HOST");
+            host = mProperties.getProperty("C2K_HOST");
             portString = mProperties.getProperty("C2K_PORT");
-            if (mC2KHost != null && portString != null) {
+            if (host != null && portString != null) {
                 try {
-                    mC2KPort = Integer.parseInt(portString);
-                    mSetC2KServer = true;
+                    int port = Integer.parseInt(portString);
+                    native_set_agps_server(AGPS_TYPE_C2K, host, port);
+                    // use MS-Based position mode if SUPL support is enabled
+                    mPositionMode = GPS_POSITION_MODE_MS_BASED;
                 } catch (NumberFormatException e) {
                     Log.e(TAG, "unable to parse C2K_PORT: " + portString);
                 }
@@ -386,10 +384,7 @@
      * data network (e.g., the Internet), false otherwise.
      */
     public boolean requiresNetwork() {
-        // We want updateNetworkState() to get called when the network state changes
-        // for XTRA and NTP time injection support.
-        return (mNtpServer != null || native_supports_xtra() ||
-                mSuplHost != null || mC2KHost != null);
+        return true;
     }
 
     public void updateNetworkState(int state) {
@@ -954,8 +949,13 @@
                  int result = mConnMgr.startUsingNetworkFeature(
                         ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
                 if (result == Phone.APN_ALREADY_ACTIVE) {
-                    native_agps_data_conn_open(mAGpsApn);
-                    mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
+                    if (mAGpsApn != null) {
+                        native_agps_data_conn_open(mAGpsApn);
+                        mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
+                    } else {
+                        Log.e(TAG, "mAGpsApn not set when receiving Phone.APN_ALREADY_ACTIVE");
+                        native_agps_data_conn_failed();
+                    }
                 } else if (result == Phone.APN_REQUEST_STARTED) {
                     mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
                 } else {
@@ -989,29 +989,6 @@
         }
     }
 
-    private boolean setAGpsServer(int type, String host, int port) {
-        try {
-            InetAddress inetAddress = InetAddress.getByName(host);
-            if (inetAddress != null) {
-                byte[] addrBytes = inetAddress.getAddress();
-                long addr = 0;
-                for (int i = 0; i < addrBytes.length; i++) {
-                    int temp = addrBytes[i];
-                    // signed -> unsigned
-                    if (temp < 0) temp = 256 + temp;
-                    addr = addr * 256 + temp;
-                }
-                // use MS-Based position mode if SUPL support is enabled
-                mPositionMode = GPS_POSITION_MODE_MS_BASED;
-                native_set_agps_server(type, (int)addr, port);
-            }
-        } catch (UnknownHostException e) {
-            Log.e(TAG, "unknown host for server " + host);
-            return false;
-        }
-        return true;
-    }
-
     private class GpsEventThread extends Thread {
 
         public GpsEventThread() {
@@ -1085,7 +1062,7 @@
                     }
                     waitTime = getWaitTime();
                 } while (!mDone && ((!mXtraDownloadRequested &&
-                        !mTimeInjectRequested && !mSetSuplServer && !mSetC2KServer && waitTime > 0)
+                        !mTimeInjectRequested && waitTime > 0)
                         || !mNetworkAvailable));
                 if (Config.LOGD) Log.d(TAG, "NetworkThread out of wake loop");
                 
@@ -1113,18 +1090,6 @@
                         }
                     }
 
-                    // Set the AGPS server addresses if we have not yet
-                    if (mSetSuplServer) {
-                        if (setAGpsServer(AGPS_TYPE_SUPL, mSuplHost, mSuplPort)) {
-                            mSetSuplServer = false;
-                        }
-                    }
-                    if (mSetC2KServer) {
-                        if (setAGpsServer(AGPS_TYPE_C2K, mC2KHost, mC2KPort)) {
-                            mSetC2KServer = false;
-                        }
-                    }
-
                     if ((mXtraDownloadRequested || 
                             (mNextXtraTime > 0 && mNextXtraTime <= System.currentTimeMillis()))
                             && xtraDownloader != null) {
@@ -1225,5 +1190,5 @@
     private native void native_agps_data_conn_open(String apn);
     private native void native_agps_data_conn_closed();
     private native void native_agps_data_conn_failed();
-    private native void native_set_agps_server(int type, int addr, int port);
+    private native void native_set_agps_server(int type, String hostname, int port);
 }
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index d16394f..397a55b 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -126,7 +126,7 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.hardware.IMediaMetadataRetriever");
+IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever");
 
 // ----------------------------------------------------------------------
 
@@ -209,4 +209,3 @@
 // ----------------------------------------------------------------------------
 
 }; // namespace android
-
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index e1bed5f..fa2d81d 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -172,7 +172,7 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(MediaPlayer, "android.hardware.IMediaPlayer");
+IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
 
 // ----------------------------------------------------------------------
 
@@ -268,4 +268,3 @@
 // ----------------------------------------------------------------------------
 
 }; // namespace android
-
diff --git a/media/libmedia/IMediaPlayerClient.cpp b/media/libmedia/IMediaPlayerClient.cpp
index da4f7ef..bf51829 100644
--- a/media/libmedia/IMediaPlayerClient.cpp
+++ b/media/libmedia/IMediaPlayerClient.cpp
@@ -46,7 +46,7 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.hardware.IMediaPlayerClient");
+IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.media.IMediaPlayerClient");
 
 // ----------------------------------------------------------------------
 
@@ -68,4 +68,3 @@
 }
 
 }; // namespace android
-
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index a79d4f7..33b3e22 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -111,7 +111,7 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.hardware.IMediaPlayerService");
+IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService");
 
 // ----------------------------------------------------------------------
 
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 53b5aa3..df7d301 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -264,7 +264,7 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(MediaRecorder, "android.hardware.IMediaRecorder");
+IMPLEMENT_META_INTERFACE(MediaRecorder, "android.media.IMediaRecorder");
 
 // ----------------------------------------------------------------------
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 6d90001..1a03900 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -158,14 +158,18 @@
                 getContext().checkCallingOrSelfPermission(
                         android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
                     PackageManager.PERMISSION_GRANTED) {
-                throw new SecurityException("Cannot write secure settings table");
-        
+                throw new SecurityException(
+                        String.format("Permission denial: writing to secure settings requires %1$s",
+                                android.Manifest.permission.WRITE_SECURE_SETTINGS));
+
         // TODO: Move gservices into its own provider so we don't need this nonsense.
         } else if ("gservices".equals(args.table) &&
             getContext().checkCallingOrSelfPermission(
                     android.Manifest.permission.WRITE_GSERVICES) !=
                 PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Cannot write gservices table");
+            throw new SecurityException(
+                    String.format("Permission denial: writing to gservices settings requires %1$s",
+                            android.Manifest.permission.WRITE_GSERVICES));
         }
     }
 
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index b50add6..e9c4ab7 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -15,9 +15,6 @@
  */
 package android.tts;
 
-import android.speech.tts.ITts.Stub;
-import android.speech.tts.ITtsCallback;
-
 import android.app.Service;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -32,6 +29,9 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.preference.PreferenceManager;
+import android.speech.tts.ITts.Stub;
+import android.speech.tts.ITtsCallback;
+import android.speech.tts.TextToSpeech;
 import android.util.Log;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -93,10 +93,6 @@
     private static final String CATEGORY = "android.intent.category.TTS";
     private static final String PKGNAME = "android.tts";
 
-    private static final int FALLBACK_TTS_DEFAULT_RATE = 100; // 1x
-    private static final int FALLBACK_TTS_DEFAULT_PITCH = 100;// 1x
-    private static final int FALLBACK_TTS_USE_DEFAULTS = 0;
-
     final RemoteCallbackList<android.speech.tts.ITtsCallback> mCallbacks = new RemoteCallbackList<ITtsCallback>();
 
     private Boolean mIsSpeaking;
@@ -162,14 +158,16 @@
 
     private boolean isDefaultEnforced() {
         return (android.provider.Settings.Secure.getInt(mResolver,
-                    android.provider.Settings.Secure.TTS_USE_DEFAULTS, FALLBACK_TTS_USE_DEFAULTS)
+                    android.provider.Settings.Secure.TTS_USE_DEFAULTS,
+                    TextToSpeech.Engine.FALLBACK_TTS_USE_DEFAULTS)
                 == 1 );
     }
 
 
     private int getDefaultRate() {
         return android.provider.Settings.Secure.getInt(mResolver,
-                android.provider.Settings.Secure.TTS_DEFAULT_RATE, FALLBACK_TTS_DEFAULT_RATE);
+                android.provider.Settings.Secure.TTS_DEFAULT_RATE,
+                TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_RATE);
     }
 
 
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 2315821..c60f981 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -31,8 +31,10 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManager;
+import android.content.pm.Signature;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
@@ -52,6 +54,9 @@
 import com.android.internal.backup.LocalTransport;
 import com.android.internal.backup.IBackupTransport;
 
+import com.android.server.PackageManagerBackupAgent;
+import com.android.server.PackageManagerBackupAgent.Metadata;
+
 import java.io.EOFException;
 import java.io.File;
 import java.io.FileDescriptor;
@@ -70,6 +75,7 @@
     private static final String TAG = "BackupManagerService";
     private static final boolean DEBUG = true;
 
+    // Default time to wait after data changes before we back up the data
     private static final long COLLECTION_INTERVAL = 1000;
     //private static final long COLLECTION_INTERVAL = 3 * 60 * 1000;
 
@@ -104,9 +110,11 @@
     // Backups that we haven't started yet.
     private HashMap<ApplicationInfo,BackupRequest> mPendingBackups
             = new HashMap<ApplicationInfo,BackupRequest>();
-    // Backups that we have started.  These are separate to prevent starvation
-    // if an app keeps re-enqueuing itself.
-    private ArrayList<BackupRequest> mBackupQueue;
+    // Do we need to back up the package manager metadata on the next pass?
+    private boolean mDoPackageManager;
+    private static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
+
+    // locking around the pending-backup management
     private final Object mQueueLock = new Object();
 
     // The thread performing the sequence of queued backups binds to each app's agent
@@ -147,7 +155,9 @@
         mJournalDir.mkdirs();
         makeJournalLocked();    // okay because no other threads are running yet
 
-        // Build our mapping of uid to backup client services
+        // Build our mapping of uid to backup client services.  This implicitly
+        // schedules a backup pass on the Package Manager metadata the first
+        // time anything needs to be backed up.
         synchronized (mBackupParticipants) {
             addPackageParticipantsLocked(null);
         }
@@ -155,7 +165,8 @@
         // Set up our transport options and initialize the default transport
         // TODO: Have transports register themselves somehow?
         // TODO: Don't create transports that we don't need to?
-        mTransportId = BackupManager.TRANSPORT_GOOGLE;
+        mTransportId = BackupManager.TRANSPORT_LOCAL;
+        //mTransportId = BackupManager.TRANSPORT_GOOGLE;
         mLocalTransport = new LocalTransport(context);  // This is actually pretty cheap
         mGoogleTransport = null;
 
@@ -286,6 +297,7 @@
                 }
 
                 // snapshot the pending-backup set and work on that
+                ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
                 File oldJournal = mJournal;
                 synchronized (mQueueLock) {
                     if (mPendingBackups.size() == 0) {
@@ -293,13 +305,11 @@
                         break;
                     }
 
-                    if (mBackupQueue == null) {
-                        mBackupQueue = new ArrayList<BackupRequest>();
-                        for (BackupRequest b: mPendingBackups.values()) {
-                            mBackupQueue.add(b);
-                        }
-                        mPendingBackups = new HashMap<ApplicationInfo,BackupRequest>();
+                    for (BackupRequest b: mPendingBackups.values()) {
+                        queue.add(b);
                     }
+                    Log.v(TAG, "clearing pending backups");
+                    mPendingBackups.clear();
 
                     // Start a new backup-queue journal file too
                     if (mJournalStream != null) {
@@ -318,7 +328,7 @@
                     // at next boot and the journaled requests fulfilled.
                 }
 
-                (new PerformBackupThread(transport, mBackupQueue, oldJournal)).start();
+                (new PerformBackupThread(transport, queue, oldJournal)).start();
                 break;
             }
 
@@ -363,12 +373,13 @@
                     mBackupParticipants.put(uid, set);
                 }
                 set.add(app);
+                backUpPackageManagerData();
             }
         }
     }
 
-    // Remove the given package's backup services from our known active set.  If
-    // 'packageName' is null, *all* backup services will be removed.
+    // Remove the given package's entry from our known active set.  If
+    // 'packageName' is null, *all* participating apps will be removed.
     void removePackageParticipantsLocked(String packageName) {
         if (DEBUG) Log.v(TAG, "removePackageParticipantsLocked: " + packageName);
         List<ApplicationInfo> allApps = null;
@@ -406,6 +417,7 @@
                     for (ApplicationInfo entry: set) {
                         if (entry.packageName.equals(app.packageName)) {
                             set.remove(entry);
+                            backUpPackageManagerData();
                             break;
                         }
                     }
@@ -418,6 +430,7 @@
 
     // Returns the set of all applications that define an android:backupAgent attribute
     private List<ApplicationInfo> allAgentApps() {
+        // !!! TODO: cache this and regenerate only when necessary
         List<ApplicationInfo> allApps = mPackageManager.getInstalledApplications(0);
         int N = allApps.size();
         if (N > 0) {
@@ -447,13 +460,29 @@
         addPackageParticipantsLockedInner(packageName, allApps);
     }
 
+    private void backUpPackageManagerData() {
+        // No need to schedule a backup just for the metadata; just piggyback on
+        // the next actual data backup.
+        synchronized(this) {
+            mDoPackageManager = true;
+        }
+    }
+
+    // The queue lock should be held when scheduling a backup pass
+    private void scheduleBackupPassLocked(long timeFromNowMillis) {
+        mBackupHandler.removeMessages(MSG_RUN_BACKUP);
+        mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, timeFromNowMillis);
+    }
+
     // Return the given transport
     private IBackupTransport getTransport(int transportID) {
         switch (transportID) {
         case BackupManager.TRANSPORT_LOCAL:
+            Log.v(TAG, "Supplying local transport");
             return mLocalTransport;
 
         case BackupManager.TRANSPORT_GOOGLE:
+            Log.v(TAG, "Supplying Google transport");
             return mGoogleTransport;
 
         default:
@@ -558,7 +587,29 @@
                 return;
             }
 
-            // The transport is up and running; now run all the backups in our queue
+            // The transport is up and running.  First, back up the package manager
+            // metadata if necessary
+            boolean doPackageManager;
+            synchronized (BackupManagerService.this) {
+                doPackageManager = mDoPackageManager;
+                mDoPackageManager = false;
+            }
+            if (doPackageManager) {
+                // The package manager doesn't have a proper <application> etc, but since
+                // it's running here in the system process we can just set up its agent
+                // directly and use a synthetic BackupRequest.
+                if (DEBUG) Log.i(TAG, "Running PM backup pass as well");
+
+                PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+                        mPackageManager, allAgentApps());
+                BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
+                pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
+                processOneBackup(pmRequest,
+                        IBackupAgent.Stub.asInterface(pmAgent.onBind()),
+                        mTransport);
+            }
+
+            // Now run all the backups in our queue
             doQueuedBackups(mTransport);
 
             // Finally, tear down the transport
@@ -609,8 +660,15 @@
                 // Look up the package info & signatures.  This is first so that if it
                 // throws an exception, there's no file setup yet that would need to
                 // be unraveled.
-                PackageInfo packInfo = mPackageManager.getPackageInfo(packageName,
+                PackageInfo packInfo;
+                if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
+                    // The metadata 'package' is synthetic
+                    packInfo = new PackageInfo();
+                    packInfo.packageName = packageName;
+                } else {
+                    packInfo = mPackageManager.getPackageInfo(packageName,
                         PackageManager.GET_SIGNATURES);
+                }
 
                 // !!! TODO: get the state file dir from the transport
                 File savedStateName = new File(mStateDir, packageName);
@@ -698,6 +756,40 @@
         return null;
     }
 
+    private boolean signaturesMatch(Signature[] storedSigs, Signature[] deviceSigs) {
+        // Allow unsigned apps, but not signed on one device and unsigned on the other
+        // !!! TODO: is this the right policy?
+        if (DEBUG) Log.v(TAG, "signaturesMatch(): stored=" + storedSigs
+                + " device=" + deviceSigs);
+        if ((storedSigs == null || storedSigs.length == 0)
+                && (deviceSigs == null || deviceSigs.length == 0)) {
+            return true;
+        }
+        if (storedSigs == null || deviceSigs == null) {
+            return false;
+        }
+
+        // !!! TODO: this demands that every stored signature match one
+        // that is present on device, and does not demand the converse.
+        // Is this this right policy?
+        int nStored = storedSigs.length;
+        int nDevice = deviceSigs.length;
+
+        for (int i=0; i < nStored; i++) {
+            boolean match = false;
+            for (int j=0; j < nDevice; j++) {
+                if (storedSigs[i].equals(deviceSigs[j])) {
+                    match = true;
+                    break;
+                }
+            }
+            if (!match) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     class PerformRestoreThread extends Thread {
         private IBackupTransport mTransport;
         private int mToken;
@@ -710,6 +802,7 @@
 
         @Override
         public void run() {
+            if (DEBUG) Log.v(TAG, "Beginning restore process");
             /**
              * Restore sequence:
              *
@@ -742,6 +835,13 @@
                         // !!! TODO: pick out the set for this token
                         mImage = images[0];
 
+                        // Pull the Package Manager metadata from the restore set first
+                        PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+                                mPackageManager, allAgentApps());
+                        PackageInfo pmApp = new PackageInfo();
+                        pmApp.packageName = PACKAGE_MANAGER_SENTINEL;
+                        processOneRestore(pmApp, IBackupAgent.Stub.asInterface(pmAgent.onBind()));
+
                         // build the set of apps we will attempt to restore
                         PackageInfo[] packages = mTransport.getAppSet(mImage.token);
                         HashSet<PackageInfo> appsToRestore = new HashSet<PackageInfo>();
@@ -749,7 +849,30 @@
                             // get the real PackageManager idea of the package
                             PackageInfo app = isRestorable(pkg);
                             if (app != null) {
-                                appsToRestore.add(app);
+                                // Validate against the backed-up signature block, too
+                                Metadata info = pmAgent.getRestoredMetadata(app.packageName);
+                                if (info != null) {
+                                    if (app.versionCode >= info.versionCode) {
+                                        if (DEBUG) Log.v(TAG, "Restore version "
+                                                + info.versionCode
+                                                + " compatible with app version "
+                                                + app.versionCode);
+                                        if (signaturesMatch(info.signatures, app.signatures)) {
+                                            appsToRestore.add(app);
+                                        } else {
+                                            Log.w(TAG, "Sig mismatch restoring "
+                                                    + app.packageName);
+                                        }
+                                    } else {
+                                        Log.i(TAG, "Restore set for " + app.packageName
+                                                + " is too new [" + info.versionCode
+                                                + "] for installed app version "
+                                                + app.versionCode);
+                                    }
+                                } else {
+                                    Log.d(TAG, "Unable to get metadata for "
+                                            + app.packageName);
+                                }
                             }
                         }
 
@@ -920,8 +1043,7 @@
                 // Schedule a backup pass in a few minutes.  As backup-eligible data
                 // keeps changing, continue to defer the backup pass until things
                 // settle down, to avoid extra overhead.
-                mBackupHandler.removeMessages(MSG_RUN_BACKUP);
-                mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, COLLECTION_INTERVAL);
+                scheduleBackupPassLocked(COLLECTION_INTERVAL);
             }
         } else {
             Log.w(TAG, "dataChanged but no participant pkg " + packageName);
@@ -947,14 +1069,14 @@
 
         if (DEBUG) Log.v(TAG, "Scheduling immediate backup pass");
         synchronized (mQueueLock) {
-            mBackupHandler.removeMessages(MSG_RUN_BACKUP);
-            mBackupHandler.sendEmptyMessage(MSG_RUN_BACKUP);
+            scheduleBackupPassLocked(0);
         }
     }
 
     // Report the currently active transport
     public int getCurrentTransport() {
         mContext.enforceCallingPermission("android.permission.BACKUP", "selectBackupTransport");
+        Log.v(TAG, "getCurrentTransport() returning " + mTransportId);
         return mTransportId;
     }
 
@@ -964,6 +1086,7 @@
 
         int prevTransport = mTransportId;
         mTransportId = transportId;
+        Log.v(TAG, "selectBackupTransport() set " + mTransportId + " returning " + prevTransport);
         return prevTransport;
     }
 
@@ -1097,11 +1220,10 @@
                     pw.println(app.toString());
                 }
             }
-            pw.println("Pending:");
-            Iterator<BackupRequest> br = mPendingBackups.values().iterator();
-            while (br.hasNext()) {
-                pw.print("    ");
-                pw.println(br);
+            pw.println("Pending: " + mPendingBackups.size());
+            for (BackupRequest req : mPendingBackups.values()) {
+                pw.print("   ");
+                pw.println(req);
             }
         }
     }
diff --git a/services/java/com/android/server/EntropyService.java b/services/java/com/android/server/EntropyService.java
index e51a0af..28f09f5 100644
--- a/services/java/com/android/server/EntropyService.java
+++ b/services/java/com/android/server/EntropyService.java
@@ -17,12 +17,16 @@
 package com.android.server;
 
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
 
 import android.os.Binder;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.Message;
+import android.os.SystemProperties;
 import android.util.Log;
 
 /**
@@ -49,6 +53,8 @@
     private static final int ENTROPY_WHAT = 1;
     private static final int ENTROPY_WRITE_PERIOD = 3 * 60 * 60 * 1000;  // 3 hrs
     private static final String RANDOM_DEV = "/dev/urandom";
+    private static final long START_TIME = System.currentTimeMillis();
+    private static final long START_NANOTIME = System.nanoTime();
 
     /**
      * Handler that periodically updates the entropy on disk.
@@ -67,6 +73,7 @@
 
     public EntropyService() {
         loadInitialEntropy();
+        addDeviceSpecificEntropy();
         writeEntropy();
         scheduleEntropyWriter();
     }
@@ -88,7 +95,47 @@
         try {
             RandomBlock.fromFile(RANDOM_DEV).toFile(ENTROPY_FILENAME);
         } catch (IOException e) {
-            Log.e(TAG, "unable to write entropy", e);
+            Log.w(TAG, "unable to write entropy", e);
+        }
+    }
+
+    /**
+     * Add additional information to the kernel entropy pool.  The
+     * information isn't necessarily "random", but that's ok.  Even
+     * sending non-random information to {@code /dev/urandom} is useful
+     * because, while it doesn't increase the "quality" of the entropy pool,
+     * it mixes more bits into the pool, which gives us a higher degree
+     * of uncertainty in the generated randomness.  Like nature, writes to
+     * the random device can only cause the quality of the entropy in the
+     * kernel to stay the same or increase.
+     *
+     * <p>For maximum effect, we try to target information which varies
+     * on a per-device basis, and is not easily observable to an
+     * attacker.
+     */
+    private void addDeviceSpecificEntropy() {
+        PrintWriter out = null;
+        try {
+            out = new PrintWriter(new FileOutputStream(RANDOM_DEV));
+            out.println("Copyright (C) 2009 The Android Open Source Project");
+            out.println("All Your Randomness Are Belong To Us");
+            out.println(START_TIME);
+            out.println(START_NANOTIME);
+            out.println(SystemProperties.get("ro.serialno"));
+            out.println(SystemProperties.get("ro.bootmode"));
+            out.println(SystemProperties.get("ro.baseband"));
+            out.println(SystemProperties.get("ro.carrier"));
+            out.println(SystemProperties.get("ro.bootloader"));
+            out.println(SystemProperties.get("ro.hardware"));
+            out.println(SystemProperties.get("ro.revision"));
+            out.println(System.currentTimeMillis());
+            out.println(System.nanoTime());
+        } catch (IOException e) {
+            Log.w(TAG, "Unable to add device specific data to the entropy pool", e);
+        } finally {
+            if (out != null) {
+                out.close();
+            }
         }
     }
 
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/PackageManagerBackupAgent.java
new file mode 100644
index 0000000..9422878
--- /dev/null
+++ b/services/java/com/android/server/PackageManagerBackupAgent.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2009 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 com.android.server;
+
+import android.app.BackupAgent;
+import android.backup.BackupDataInput;
+import android.backup.BackupDataOutput;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.Signature;
+import android.os.Build;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * We back up the signatures of each package so that during a system restore,
+ * we can verify that the app whose data we think we have matches the app
+ * actually resident on the device.
+ *
+ * Since the Package Manager isn't a proper "application" we just provide a
+ * direct IBackupAgent implementation and hand-construct it at need.
+ */
+public class PackageManagerBackupAgent extends BackupAgent {
+    private static final String TAG = "PMBA";
+    private static final boolean DEBUG = true;
+
+    // key under which we store global metadata (individual app metadata
+    // is stored using the package name as a key)
+    private static final String GLOBAL_METADATA_KEY = "@meta@";
+
+    private List<ApplicationInfo> mAllApps;
+    private PackageManager mPackageManager;
+    private HashMap<String, Metadata> mRestoredSignatures;
+
+    public class Metadata {
+        public int versionCode;
+        public Signature[] signatures;
+
+        Metadata(int version, Signature[] sigs) {
+            versionCode = version;
+            signatures = sigs;
+        }
+    }
+
+    // We're constructed with the set of applications that are participating
+    // in backup.  This set changes as apps are installed & removed.
+    PackageManagerBackupAgent(PackageManager packageMgr, List<ApplicationInfo> apps) {
+        mPackageManager = packageMgr;
+        mAllApps = apps;
+        mRestoredSignatures = null;
+    }
+
+    public Metadata getRestoredMetadata(String packageName) {
+        if (mRestoredSignatures == null) {
+            Log.w(TAG, "getRestoredMetadata() before metadata read!");
+            return null;
+        }
+
+        return mRestoredSignatures.get(packageName);
+    }
+    
+    // The backed up data is the signature block for each app, keyed by
+    // the package name.
+    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState) {
+        if (DEBUG) Log.v(TAG, "onBackup()");
+
+        ByteArrayOutputStream bufStream = new ByteArrayOutputStream();  // we'll reuse these
+        DataOutputStream outWriter = new DataOutputStream(bufStream);
+        HashSet<String> existing = parseStateFile(oldState);
+
+        try {
+            /*
+             * Global metadata:
+             *
+             * int version -- the SDK version of the OS itself on the device
+             *                that produced this backup set.  Used to reject
+             *                backups from later OSes onto earlier ones.
+             */
+            if (!existing.contains(GLOBAL_METADATA_KEY)) {
+                if (DEBUG) Log.v(TAG, "Storing global metadata key");
+                outWriter.writeInt(Build.VERSION.SDK_INT);
+                byte[] metadata = bufStream.toByteArray();
+                data.writeEntityHeader(GLOBAL_METADATA_KEY, metadata.length);
+                data.writeEntityData(metadata, metadata.length);
+            } else {
+                if (DEBUG) Log.v(TAG, "Global metadata key already stored");
+            }
+
+            // For each app we have on device, see if we've backed it up yet.  If not,
+            // write its signature block to the output, keyed on the package name.
+            for (ApplicationInfo app : mAllApps) {
+                String packName = app.packageName;
+                if (!existing.contains(packName)) {
+                    // We haven't stored this app's signatures yet, so we do that now
+                    try {
+                        PackageInfo info = mPackageManager.getPackageInfo(packName,
+                                PackageManager.GET_SIGNATURES);
+                        /*
+                         * Metadata for each package:
+                         *
+                         * int version       -- [4] the package's versionCode
+                         * byte[] signatures -- [len] flattened Signature[] of the package
+                         */
+
+                        // marshall the version code in a canonical form
+                        bufStream.reset();
+                        outWriter.writeInt(info.versionCode);
+                        byte[] versionBuf = bufStream.toByteArray();
+
+                        byte[] sigs = flattenSignatureArray(info.signatures);
+
+                        // !!! TODO: take out this debugging
+                        if (DEBUG) {
+                            Log.v(TAG, "+ metadata for " + packName
+                                    + " version=" + info.versionCode
+                                    + " versionLen=" + versionBuf.length
+                                    + " sigsLen=" + sigs.length);
+                        }
+                        // Now we can write the backup entity for this package
+                        data.writeEntityHeader(packName, versionBuf.length + sigs.length);
+                        data.writeEntityData(versionBuf, versionBuf.length);
+                        data.writeEntityData(sigs, sigs.length);
+                    } catch (NameNotFoundException e) {
+                        // Weird; we just found it, and now are told it doesn't exist.
+                        // Treat it as having been removed from the device.
+                        existing.add(packName);
+                    }
+                } else {
+                    // We've already backed up this app.  Remove it from the set so
+                    // we can tell at the end what has disappeared from the device.
+                    // !!! TODO: take out the debugging message
+                    if (DEBUG) Log.v(TAG, "= already backed up metadata for " + packName);
+                    if (!existing.remove(packName)) {
+                        Log.d(TAG, "*** failed to remove " + packName + " from package set!");
+                    }
+                }
+            }
+
+            // At this point, the only entries in 'existing' are apps that were
+            // mentioned in the saved state file, but appear to no longer be present
+            // on the device.  Write a deletion entity for them.
+            for (String app : existing) {
+                // !!! TODO: take out this msg
+                if (DEBUG) Log.v(TAG, "- removing metadata for deleted pkg " + app);
+                try {
+                    data.writeEntityHeader(app, -1);
+                } catch (IOException e) {
+                    Log.e(TAG, "Unable to write package deletions!");
+                    return;
+                }
+            }
+        } catch (IOException e) {
+            // Real error writing data
+            Log.e(TAG, "Unable to write package backup data file!");
+            return;
+        }
+
+        // Finally, write the new state blob -- just the list of all apps we handled
+        writeStateFile(mAllApps, newState);
+    }
+
+    // "Restore" here is a misnomer.  What we're really doing is reading back the
+    // set of app signatures associated with each backed-up app in this restore
+    // image.  We'll use those later to determine what we can legitimately restore.
+    public void onRestore(BackupDataInput data, ParcelFileDescriptor newState)
+            throws IOException {
+        List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>();
+        HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>();
+        if (DEBUG) Log.v(TAG, "onRestore()");
+        int storedSystemVersion = -1;
+
+        while (data.readNextHeader()) {
+            String key = data.getKey();
+            int dataSize = data.getDataSize();
+
+            if (DEBUG) Log.v(TAG, "   got key=" + key + " dataSize=" + dataSize);
+
+            // generic setup to parse any entity data
+            byte[] dataBuf = new byte[dataSize];
+            data.readEntityData(dataBuf, 0, dataSize);
+            ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
+            DataInputStream in = new DataInputStream(baStream);
+
+            if (key.equals(GLOBAL_METADATA_KEY)) {
+                storedSystemVersion = in.readInt();
+                if (DEBUG) Log.v(TAG, "   storedSystemVersion = " + storedSystemVersion);
+                if (storedSystemVersion > Build.VERSION.SDK_INT) {
+                    // returning before setting the sig map means we rejected the restore set
+                    Log.w(TAG, "Restore set was from a later version of Android; not restoring");
+                    return;
+                }
+                // !!! TODO: remove this debugging output
+                if (DEBUG) {
+                    Log.i(TAG, "Restore set version " + storedSystemVersion
+                            + " is compatible with OS version " + Build.VERSION.SDK_INT);
+                }
+            } else {
+                // it's a file metadata record
+                int versionCode = in.readInt();
+                Signature[] sigs = unflattenSignatureArray(in);
+//              !!! TODO: take out this debugging
+                if (DEBUG) {
+                    Log.i(TAG, "   restored metadata for " + key
+                            + " dataSize=" + dataSize
+                            + " versionCode=" + versionCode + " sigs=" + sigs);
+                }
+
+                ApplicationInfo app = new ApplicationInfo();
+                app.packageName = key;
+                restoredApps.add(app);
+                sigMap.put(key, new Metadata(versionCode, sigs));
+            }
+        }
+
+        // On successful completion, cache the signature map for the Backup Manager to use
+        mRestoredSignatures = sigMap;
+    }
+
+
+    // Util: convert an array of Signatures into a flattened byte buffer.  The
+    // flattened format contains enough info to reconstruct the signature array.
+    private byte[] flattenSignatureArray(Signature[] allSigs) {
+        ByteArrayOutputStream outBuf = new ByteArrayOutputStream();
+        DataOutputStream out = new DataOutputStream(outBuf);
+
+        // build the set of subsidiary buffers
+        try {
+            // first the # of signatures in the array
+            out.writeInt(allSigs.length);
+
+            // then the signatures themselves, length + flattened buffer
+            for (Signature sig : allSigs) {
+                byte[] flat = sig.toByteArray();
+                out.writeInt(flat.length);
+                out.write(flat);
+            }
+        } catch (IOException e) {
+            // very strange; we're writing to memory here.  abort.
+            return null;
+        }
+
+        return outBuf.toByteArray();
+    }
+
+    private Signature[] unflattenSignatureArray(/*byte[] buffer*/ DataInputStream in) {
+        Signature[] sigs = null;
+
+        try {
+            int num = in.readInt();
+            Log.v(TAG, " ... unflatten read " + num);
+            sigs = new Signature[num];
+            for (int i = 0; i < num; i++) {
+                int len = in.readInt();
+                byte[] flatSig = new byte[len];
+                in.read(flatSig);
+                sigs[i] = new Signature(flatSig);
+            }
+        } catch (EOFException e) {
+            // clean termination
+            if (sigs == null) {
+                Log.w(TAG, "Empty signature block found");
+            }
+        } catch (IOException e) {
+            Log.d(TAG, "Unable to unflatten sigs");
+            return null;
+        }
+
+        return sigs;
+    }
+
+    // Util: parse out an existing state file into a usable structure
+    private HashSet<String> parseStateFile(ParcelFileDescriptor stateFile) {
+        HashSet<String> set = new HashSet<String>();
+        // The state file is just the list of app names we have stored signatures for
+        FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor());
+        DataInputStream in = new DataInputStream(instream);
+
+        int bufSize = 256;
+        byte[] buf = new byte[bufSize];
+        try {
+            int nameSize = in.readInt();
+            if (bufSize < nameSize) {
+                bufSize = nameSize + 32;
+                buf = new byte[bufSize];
+            }
+            in.read(buf, 0, nameSize);
+            String pkg = new String(buf, 0, nameSize);
+            set.add(pkg);
+        } catch (EOFException eof) {
+            // safe; we're done
+        } catch (IOException e) {
+            // whoops, bad state file.  abort.
+            Log.e(TAG, "Unable to read Package Manager state file");
+            return null;
+        }
+        return set;
+    }
+
+    // Util: write out our new backup state file
+    private void writeStateFile(List<ApplicationInfo> apps, ParcelFileDescriptor stateFile) {
+        FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
+        DataOutputStream out = new DataOutputStream(outstream);
+
+        try {
+            // by the time we get here we know we've stored the global metadata record
+            byte[] metaNameBuf = GLOBAL_METADATA_KEY.getBytes();
+            out.writeInt(metaNameBuf.length);
+            out.write(metaNameBuf);
+
+            // now write all the app names too
+            for (ApplicationInfo app : apps) {
+                byte[] pkgNameBuf = app.packageName.getBytes();
+                out.writeInt(pkgNameBuf.length);
+                out.write(pkgNameBuf);
+            }
+        } catch (IOException e) {
+            Log.e(TAG, "Unable to write package manager state file!");
+            return;
+        }
+    }
+}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index cef4e01..d2e5555 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -19,7 +19,6 @@
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
-import com.android.server.PackageManagerService.PreferredActivity;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -27,10 +26,7 @@
 
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
 import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -152,6 +148,7 @@
     
     final Context mContext;
     final boolean mFactoryTest;
+    final boolean mNoDexOpt;
     final DisplayMetrics mMetrics;
     final int mDefParseFlags;
     final String[] mSeparateProcesses;
@@ -303,6 +300,7 @@
         
         mContext = context;
         mFactoryTest = factoryTest;
+        mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
         mMetrics = new DisplayMetrics();
         mSettings = new Settings();
         mSettings.addSharedUserLP("android.uid.system",
@@ -372,6 +370,10 @@
                     startTime);
             
             int scanMode = SCAN_MONITOR;
+            if (mNoDexOpt) {
+                Log.w(TAG, "Running ENG build: no pre-dexopt!");
+                scanMode |= SCAN_NO_DEX; 
+            }
             
             final HashSet<String> libFiles = new HashSet<String>();
             
@@ -932,33 +934,7 @@
         });
     }
 
-    public void freeStorage(final long freeStorageSize, final PendingIntent opFinishedIntent) {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.CLEAR_APP_CACHE, null);
-        // Queue up an async operation since clearing cache may take a little while.
-        mHandler.post(new Runnable() {
-            public void run() {
-                mHandler.removeCallbacks(this);
-                int retCode = -1;
-                if (mInstaller != null) {
-                    retCode = mInstaller.freeCache(freeStorageSize);
-                    if (retCode < 0) {
-                        Log.w(TAG, "Couldn't clear application caches");
-                    }
-                }
-                if(opFinishedIntent != null) {
-                    try {
-                        // Callback via pending intent
-                        opFinishedIntent.send((retCode >= 0) ? 1 : 0);
-                    } catch (CanceledException e1) {
-                        Log.i(TAG, "Failed to send pending intent");
-                    }
-                }
-            }
-        });
-    }
-
-    public void freeStorageWithIntent(final long freeStorageSize, final IntentSender pi) {
+    public void freeStorage(final long freeStorageSize, final IntentSender pi) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CLEAR_APP_CACHE, null);
         // Queue up an async operation since clearing cache may take a little while.
@@ -993,10 +969,11 @@
             if (Config.LOGV) Log.v(TAG, "getActivityInfo " + component + ": " + a);
             if (a != null && mSettings.isEnabledLP(a.info, flags)) {
                 ActivityInfo ainfo = PackageParser.generateActivityInfo(a, flags);
-                if (ainfo != null && (flags & PackageManager.GET_EXPANDABLE) != 0) {
+                if (ainfo != null) {
                     ApplicationInfo appInfo = getApplicationInfo(component.getPackageName(),
-                            PackageManager.GET_EXPANDABLE | PackageManager.GET_SUPPORTS_DENSITIES); 
-                    if (appInfo != null && !appInfo.expandable) {
+                            PackageManager.GET_SUPPORTS_DENSITIES);
+                    if (appInfo != null &&
+                            (appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) == 0) {
                         // Check if the screen size is same as what the application expect.
                         CompatibilityInfo info = new CompatibilityInfo(appInfo);
                         DisplayMetrics metrics = new DisplayMetrics();
@@ -1009,11 +986,13 @@
                             // Don't allow an app that cannot expand to handle rotation.
                             ainfo.configChanges &= ~ ActivityInfo.CONFIG_ORIENTATION;
                         } else {
-                            appInfo.expandable = true;
+                            appInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
                         }
                         if (DEBUG_SETTINGS) {
                             Log.d(TAG, "component=" + component +
-                                    ", expandable:" + appInfo.expandable);
+                                    ", expandable:" +
+                                    ((appInfo.flags &
+                                            ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0));
                         }
                     }
                 }
@@ -1946,7 +1925,56 @@
         }
         return true;
     }
+    
+    public boolean performDexOpt(String packageName) {
+        if (!mNoDexOpt) {
+            return false;
+        }
         
+        PackageParser.Package p;
+        synchronized (mPackages) {
+            p = mPackages.get(packageName);
+            if (p == null || p.mDidDexOpt) {
+                return false;
+            }
+        }
+        synchronized (mInstallLock) {
+            return performDexOptLI(p, false) == DEX_OPT_PERFORMED;
+        }
+    }
+    
+    static final int DEX_OPT_SKIPPED = 0;
+    static final int DEX_OPT_PERFORMED = 1;
+    static final int DEX_OPT_FAILED = -1;
+    
+    private int performDexOptLI(PackageParser.Package pkg, boolean forceDex) {
+        boolean performed = false;
+        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
+            String path = pkg.mScanPath;
+            int ret = 0;
+            try {
+                if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) {
+                    ret = mInstaller.dexopt(path, pkg.applicationInfo.uid, 
+                            !pkg.mForwardLocked);
+                    pkg.mDidDexOpt = true;
+                    performed = true;
+                }
+            } catch (FileNotFoundException e) {
+                Log.w(TAG, "Apk not found for dexopt: " + path);
+                ret = -1;
+            } catch (IOException e) {
+                Log.w(TAG, "Exception reading apk: " + path, e);
+                ret = -1;
+            }
+            if (ret < 0) {
+                //error from installer
+                return DEX_OPT_FAILED;
+            }
+        }
+        
+        return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
+    }
+    
     private PackageParser.Package scanPackageLI(
         File scanFile, File destCodeFile, File destResourceFile,
         PackageParser.Package pkg, int parseFlags, int scanMode) {
@@ -2242,23 +2270,11 @@
                 }
             }
 
-            if ((scanMode&SCAN_NO_DEX) == 0
-                    && (pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
-                int ret = 0;
-                try {
-                    if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) {
-                        ret = mInstaller.dexopt(path, pkg.applicationInfo.uid, 
-                                (scanMode&SCAN_FORWARD_LOCKED) == 0);
-                    }
-                } catch (FileNotFoundException e) {
-                    Log.w(TAG, "Apk not found for dexopt: " + path);
-                    ret = -1;
-                } catch (IOException e) {
-                    Log.w(TAG, "Exception reading apk: " + path, e);
-                    ret = -1;
-                }
-                if (ret < 0) {
-                    //error from installer
+            pkg.mForwardLocked = (scanMode&SCAN_FORWARD_LOCKED) != 0;
+            pkg.mScanPath = path;
+            
+            if ((scanMode&SCAN_NO_DEX) == 0) {
+                if (performDexOptLI(pkg, forceDex) == DEX_OPT_FAILED) {
                     mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
                     return null;
                 }
@@ -5921,7 +5937,7 @@
                     continue;
                 }
                 for (PackageSetting pkg:sus.packages) {
-                    if (pkg.grantedPermissions.contains (eachPerm)) {
+                    if (pkg.pkg.requestedPermissions.contains(eachPerm)) {
                         used = true;
                         break;
                     }
diff --git a/services/java/com/android/server/RandomBlock.java b/services/java/com/android/server/RandomBlock.java
index c08761e..4ac1c6e 100644
--- a/services/java/com/android/server/RandomBlock.java
+++ b/services/java/com/android/server/RandomBlock.java
@@ -19,12 +19,12 @@
 import android.util.Log;
 
 import java.io.Closeable;
+import java.io.DataOutput;
 import java.io.EOFException;
 import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
+import java.io.RandomAccessFile;
 
 /**
  * A 4k block of random {@code byte}s.
@@ -63,17 +63,27 @@
 
     void toFile(String filename) throws IOException {
         Log.v(TAG, "writing to file " + filename);
-        OutputStream out = null;
+        RandomAccessFile out = null;
         try {
-            // TODO: Investigate using RandomAccessFile
-            out = new FileOutputStream(filename);
-            toStream(out);
+            out = new RandomAccessFile(filename, "rws");
+            toDataOut(out);
+            truncateIfPossible(out);
         } finally {
             close(out);
         }
     }
 
-    private void toStream(OutputStream out) throws IOException {
+    private static void truncateIfPossible(RandomAccessFile f) {
+        try {
+            f.setLength(BLOCK_SIZE);
+        } catch (IOException e) {
+            // ignore this exception.  Sometimes, the file we're trying to
+            // write is a character device, such as /dev/urandom, and
+            // these character devices do not support setting the length.
+        }
+    }
+
+    private void toDataOut(DataOutput out) throws IOException {
         out.write(block);
     }
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 045e636..ac176ca 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -181,7 +181,7 @@
 
     // The flags that are set for all calls we make to the package manager.
     static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES
-            | PackageManager.GET_SUPPORTS_DENSITIES | PackageManager.GET_EXPANDABLE;
+            | PackageManager.GET_SUPPORTS_DENSITIES;
     
     private static final String SYSTEM_SECURE = "ro.secure";
 
@@ -315,6 +315,12 @@
     // Memory pages are 4K.
     static final int PAGE_SIZE = 4*1024;
     
+    // System property defining error report receiver for system apps
+    static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
+
+    // System property defining default error report receiver
+    static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
+
     // Corresponding memory levels for above adjustments.
     final int EMPTY_APP_MEM;
     final int HIDDEN_APP_MEM;
@@ -809,6 +815,12 @@
      */
     int[] mProcDeaths = new int[20];
     
+    /**
+     * This is set if we had to do a delayed dexopt of an app before launching
+     * it, to increasing the ANR timeouts in that case.
+     */
+    boolean mDidDexOpt;
+    
     String mDebugApp = null;
     boolean mWaitForDebugger = false;
     boolean mDebugTransient = false;
@@ -1007,6 +1019,12 @@
                 processNextBroadcast(true);
             } break;
             case BROADCAST_TIMEOUT_MSG: {
+                if (mDidDexOpt) {
+                    mDidDexOpt = false;
+                    Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
+                    mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
+                    return;
+                }
                 broadcastTimeout();
             } break;
             case PAUSE_TIMEOUT_MSG: {
@@ -1017,9 +1035,16 @@
                 activityPaused(token, null, true);
             } break;
             case IDLE_TIMEOUT_MSG: {
-                IBinder token = (IBinder)msg.obj;
+                if (mDidDexOpt) {
+                    mDidDexOpt = false;
+                    Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
+                    nmsg.obj = msg.obj;
+                    mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
+                    return;
+                }
                 // We don't at this point know if the activity is fullscreen,
                 // so we need to be conservative and assume it isn't.
+                IBinder token = (IBinder)msg.obj;
                 Log.w(TAG, "Activity idle timeout for " + token);
                 activityIdleInternal(token, true);
             } break;
@@ -1035,6 +1060,13 @@
                 activityIdle(token);
             } break;
             case SERVICE_TIMEOUT_MSG: {
+                if (mDidDexOpt) {
+                    mDidDexOpt = false;
+                    Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
+                    nmsg.obj = msg.obj;
+                    mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
+                    return;
+                }
                 serviceTimeout((ProcessRecord)msg.obj);
             } break;
             case UPDATE_TIME_ZONE: {
@@ -1071,6 +1103,12 @@
                 }
             } break;
             case LAUNCH_TIMEOUT_MSG: {
+                if (mDidDexOpt) {
+                    mDidDexOpt = false;
+                    Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
+                    mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
+                    return;
+                }
                 synchronized (ActivityManagerService.this) {
                     if (mLaunchingActivity.isHeld()) {
                         Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
@@ -1091,6 +1129,13 @@
                 }
             }
             case PROC_START_TIMEOUT_MSG: {
+                if (mDidDexOpt) {
+                    mDidDexOpt = false;
+                    Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
+                    nmsg.obj = msg.obj;
+                    mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
+                    return;
+                }
                 ProcessRecord app = (ProcessRecord)msg.obj;
                 synchronized (ActivityManagerService.this) {
                     processStartTimedOutLocked(app);
@@ -1607,6 +1652,16 @@
         return proc;
     }
 
+    private void ensurePackageDexOpt(String packageName) {
+        IPackageManager pm = ActivityThread.getPackageManager();
+        try {
+            if (pm.performDexOpt(packageName)) {
+                mDidDexOpt = true;
+            }
+        } catch (RemoteException e) {
+        }
+    }
+    
     private boolean isNextTransitionForward() {
         int transit = mWindowManager.getPendingAppTransition();
         return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
@@ -1666,6 +1721,7 @@
             if (r.isHomeActivity) {
                 mHomeProcess = app;
             }
+            ensurePackageDexOpt(r.intent.getComponent().getPackageName());
             app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
                     r.info, r.icicle, results, newIntents, !andResume,
                     isNextTransitionForward());
@@ -4819,6 +4875,10 @@
                 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
                         || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
             }
+            ensurePackageDexOpt(app.info.packageName);
+            if (app.instrumentationInfo != null) {
+                ensurePackageDexOpt(app.instrumentationInfo.packageName);
+            }
             thread.bindApplication(processName, app.instrumentationInfo != null
                     ? app.instrumentationInfo : app.info, providers,
                     app.instrumentationClass, app.instrumentationProfileFile,
@@ -4907,6 +4967,7 @@
         // Check whether the next backup agent is in this process...
         if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
             if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
+            ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
             try {
                 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
             } catch (Exception e) {
@@ -6918,6 +6979,7 @@
                 }
                 app.pubProviders.put(cpi.name, cpr);
                 app.addPackage(cpi.applicationInfo.packageName);
+                ensurePackageDexOpt(cpi.applicationInfo.packageName);
             }
         }
         return providers;
@@ -7894,27 +7956,62 @@
 
     private ComponentName getErrorReportReceiver(ProcessRecord app) {
         IPackageManager pm = ActivityThread.getPackageManager();
+
         try {
-            // was an installer package name specified when this app was
-            // installed?
-            String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
-            if (installerPackageName == null) {
-                return null;
+            // look for receiver in the installer package
+            String candidate = pm.getInstallerPackageName(app.info.packageName);
+            ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
+            if (result != null) {
+                return result;
             }
 
-            // is there an Activity in this package that handles ACTION_APP_ERROR?
-            Intent intent = new Intent(Intent.ACTION_APP_ERROR);
-            intent.setPackage(installerPackageName);
-            ResolveInfo info = pm.resolveIntent(intent, null, 0);
-            if (info == null || info.activityInfo == null) {
-                return null;
+            // if the error app is on the system image, look for system apps
+            // error receiver
+            if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+                candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
+                result = getErrorReportReceiver(pm, app.info.packageName, candidate);
+                if (result != null) {
+                    return result;
+                }
             }
 
-            return new ComponentName(installerPackageName, info.activityInfo.name);
+            // if there is a default receiver, try that
+            candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
+            return getErrorReportReceiver(pm, app.info.packageName, candidate);
         } catch (RemoteException e) {
-            // will return null and no error report will be delivered
+            // should not happen
+            Log.e(TAG, "error talking to PackageManager", e);
+            return null;
         }
-        return null;
+    }
+
+    /**
+     * Return activity in receiverPackage that handles ACTION_APP_ERROR.
+     *
+     * @param pm PackageManager isntance
+     * @param errorPackage package which caused the error
+     * @param receiverPackage candidate package to receive the error
+     * @return activity component within receiverPackage which handles
+     * ACTION_APP_ERROR, or null if not found
+     */
+    private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
+            String receiverPackage) throws RemoteException {
+        if (receiverPackage == null || receiverPackage.length() == 0) {
+            return null;
+        }
+
+        // break the loop if it's the error report receiver package that crashed
+        if (receiverPackage.equals(errorPackage)) {
+            return null;
+        }
+
+        Intent intent = new Intent(Intent.ACTION_APP_ERROR);
+        intent.setPackage(receiverPackage);
+        ResolveInfo info = pm.resolveIntent(intent, null, 0);
+        if (info == null || info.activityInfo == null) {
+            return null;
+        }
+        return new ComponentName(receiverPackage, info.activityInfo.name);
     }
 
     void makeAppNotRespondingLocked(ProcessRecord app,
@@ -9542,6 +9639,7 @@
             synchronized (r.stats.getBatteryStats()) {
                 r.stats.startLaunchedLocked();
             }
+            ensurePackageDexOpt(r.serviceInfo.packageName);
             app.thread.scheduleCreateService(r, r.serviceInfo);
             created = true;
         } finally {
@@ -11098,6 +11196,7 @@
             if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
                     "Delivering to component " + r.curComponent
                     + ": " + r);
+            ensurePackageDexOpt(r.intent.getComponent().getPackageName());
             app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                     r.resultCode, r.resultData, r.resultExtras, r.ordered);
             started = true;
diff --git a/services/java/com/android/server/am/HistoryRecord.java b/services/java/com/android/server/am/HistoryRecord.java
index 944ea02..b3fc313 100644
--- a/services/java/com/android/server/am/HistoryRecord.java
+++ b/services/java/com/android/server/am/HistoryRecord.java
@@ -463,6 +463,12 @@
                     return false;
                 }
                 
+                if (service.mDidDexOpt) {
+                    // Give more time since we were dexopting.
+                    service.mDidDexOpt = false;
+                    return false;
+                }
+                
                 if (r.app.instrumentationClass == null) { 
                     service.appNotRespondingLocked(r.app, r, "keyDispatchingTimedOut");
                 } else {
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index b59fe54..059dc7b 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -707,6 +707,23 @@
                 b.setView(v);
                 b.setIcon(android.R.drawable.ic_dialog_alert);
                 b.setPositiveButton(android.R.string.ok, null);
+                
+                final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+                        | Intent.FLAG_ACTIVITY_NO_HISTORY);
+                if (intent.resolveActivity(mContext.getPackageManager()) != null) {
+                    b.setNegativeButton(com.android.internal.R.string.battery_low_why,
+                            new DialogInterface.OnClickListener() {
+                        public void onClick(DialogInterface dialog, int which) {
+                            mContext.startActivity(intent);
+                            if (mLowBatteryDialog != null) {
+                                mLowBatteryDialog.dismiss();
+                            }
+                        }
+                    });
+                }
 
             AlertDialog d = b.create();
             d.setOnDismissListener(mLowBatteryListener);
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 9395d66..890f930 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -22,7 +22,6 @@
 import android.text.TextUtils;
 
 import com.android.internal.telephony.EncodeException;
-import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.ISms;
 import com.android.internal.telephony.IccConstants;
 import com.android.internal.telephony.SmsRawData;
@@ -31,14 +30,12 @@
 import java.util.Arrays;
 import java.util.List;
 
-import static android.telephony.SmsMessage.ENCODING_7BIT;
-import static android.telephony.SmsMessage.ENCODING_8BIT;
-import static android.telephony.SmsMessage.ENCODING_16BIT;
-import static android.telephony.SmsMessage.ENCODING_UNKNOWN;
-import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES;
-import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER;
-import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS;
-import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER;
+/*
+ * TODO(code review): Curious question... Why are a lot of these
+ * methods not declared as static, since they do not seem to require
+ * any local object state?  Assumedly this cannot be changed without
+ * interfering with the API...
+ */
 
 /**
  * Manages SMS operations such as sending data, text, and pdu SMS messages.
@@ -88,7 +85,7 @@
     }
 
     /**
-     * Divide a text message into several messages, none bigger than
+     * Divide a message text into several fragments, none bigger than
      * the maximum SMS message size.
      *
      * @param text the original message.  Must not be null.
@@ -96,40 +93,7 @@
      *   comprise the original message
      */
     public ArrayList<String> divideMessage(String text) {
-        int size = text.length();
-        int[] params = SmsMessage.calculateLength(text, false);
-            /* SmsMessage.calculateLength returns an int[4] with:
-             *   int[0] being the number of SMS's required,
-             *   int[1] the number of code units used,
-             *   int[2] is the number of code units remaining until the next message.
-             *   int[3] is the encoding type that should be used for the message.
-             */
-        int messageCount = params[0];
-        int encodingType = params[3];
-        ArrayList<String> result = new ArrayList<String>(messageCount);
-
-        int start = 0;
-        int limit;
-
-        if (messageCount > 1) {
-            limit = (encodingType == ENCODING_7BIT)?
-                MAX_USER_DATA_SEPTETS_WITH_HEADER: MAX_USER_DATA_BYTES_WITH_HEADER;
-        } else {
-            limit = (encodingType == ENCODING_7BIT)?
-                MAX_USER_DATA_SEPTETS: MAX_USER_DATA_BYTES;
-        }
-
-        try {
-            while (start < size) {
-                int end = GsmAlphabet.findLimitIndex(text, start, limit, encodingType);
-                result.add(text.substring(start, end));
-                start = end;
-            }
-        }
-        catch (EncodeException e) {
-            // ignore it.
-        }
-        return result;
+        return SmsMessage.fragmentText(text);
     }
 
     /**
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index b60da5a..775b034 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -17,12 +17,17 @@
 package android.telephony;
 
 import android.os.Parcel;
+import android.util.Log;
 
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.EncodeException;
 import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.SmsMessageBase;
 import com.android.internal.telephony.SmsMessageBase.SubmitPduBase;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
+
+import java.lang.Math;
+import java.util.ArrayList;
 
 import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
 
@@ -44,19 +49,41 @@
         UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3;
     }
 
-    /** Unknown encoding scheme (see TS 23.038) */
+    /**
+     * TODO(cleanup): given that we now have more than one possible
+     * 7bit encoding, this result starts to look rather vague and
+     * maybe confusing...  If this is just an indication of code unit
+     * size, maybe that is no problem.  Otherwise, should we try to
+     * create an aggregate collection of GSM and CDMA encodings?  CDMA
+     * contains a superset of the encodings we use (it does not
+     * support 8-bit GSM, but we also do not use that encoding
+     * currently)...  We could get rid of these and directly reference
+     * the CDMA encoding definitions...
+     */
+
+    /** User data text encoding code unit size */
     public static final int ENCODING_UNKNOWN = 0;
-    /** 7-bit encoding scheme (see TS 23.038) */
     public static final int ENCODING_7BIT = 1;
-    /** 8-bit encoding scheme (see TS 23.038) */
     public static final int ENCODING_8BIT = 2;
-    /** 16-bit encoding scheme (see TS 23.038) */
     public static final int ENCODING_16BIT = 3;
 
     /** The maximum number of payload bytes per message */
     public static final int MAX_USER_DATA_BYTES = 140;
 
     /**
+     * TODO(cleanup): It would be more flexible and less fragile to
+     * rewrite this (meaning get rid of the following constant) such
+     * that an actual UDH is taken into consideration (meaning its
+     * length is measured), allowing for messages that actually
+     * contain other UDH fields...  Hence it is actually a shame to
+     * extend the API with this constant.  If necessary, maybe define
+     * the size of such a header and let the math for calculating
+     * max_octets/septets be done elsewhere.  And, while I am griping,
+     * if we use the word septet, we should use the word octet in
+     * corresponding places, not byte...
+     */
+
+    /**
      * The maximum number of payload bytes per message if a user data header
      * is present.  This assumes the header only contains the
      * CONCATENATED_8_BIT_REFERENCE element.
@@ -222,6 +249,15 @@
         }
     }
 
+    /*
+     * TODO(cleanup): It would make some sense if the result of
+     * preprocessing a message to determine the proper encoding (ie
+     * the resulting datastructure from calculateLength) could be
+     * passed as an argument to the actual final encoding function.
+     * This would better ensure that the logic behind size calculation
+     * actually matched the encoding.
+     */
+
     /**
      * Calculates the number of SMS's required to encode the message body and
      * the number of characters remaining until the next message.
@@ -232,46 +268,76 @@
      *         space chars.  If false, and if the messageBody contains
      *         non-7-bit encodable characters, length is calculated
      *         using a 16-bit encoding.
-     * @return an int[4] with int[0] being the number of SMS's required, int[1]
-     *         the number of code units used, and int[2] is the number of code
-     *         units remaining until the next message. int[3] is the encoding
-     *         type that should be used for the message.
+     * @return an int[4] with int[0] being the number of SMS's
+     *         required, int[1] the number of code units used, and
+     *         int[2] is the number of code units remaining until the
+     *         next message. int[3] is an indicator of the encoding
+     *         code unit size (see the ENCODING_* definitions in this
+     *         class).
      */
     public static int[] calculateLength(CharSequence msgBody, boolean use7bitOnly) {
         int activePhone = TelephonyManager.getDefault().getPhoneType();
+        TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ?
+            com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly) :
+            com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly);
         int ret[] = new int[4];
+        ret[0] = ted.msgCount;
+        ret[1] = ted.codeUnitCount;
+        ret[2] = ted.codeUnitsRemaining;
+        ret[3] = ted.codeUnitSize;
+        return ret;
+    }
 
-        int septets = (PHONE_TYPE_CDMA == activePhone) ?
-                com.android.internal.telephony.cdma.SmsMessage.calc7bitEncodedLength(msgBody,
-                        use7bitOnly) :
-                com.android.internal.telephony.gsm.SmsMessage.calc7bitEncodedLength(msgBody,
-                        use7bitOnly);
-        if (septets != -1) {
-            ret[1] = septets;
-            if (septets > MAX_USER_DATA_SEPTETS) {
-                ret[0] = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1;
-                ret[2] = MAX_USER_DATA_SEPTETS_WITH_HEADER
-                            - (septets % MAX_USER_DATA_SEPTETS_WITH_HEADER);
-            } else {
-                ret[0] = 1;
-                ret[2] = MAX_USER_DATA_SEPTETS - septets;
-            }
-            ret[3] = ENCODING_7BIT;
+    /**
+     * Divide a message text into several fragments, none bigger than
+     * the maximum SMS message text size.
+     *
+     * @param text text, must not be null.
+     * @return an <code>ArrayList</code> of strings that, in order,
+     *   comprise the original msg text
+     */
+    public static ArrayList<String> fragmentText(String text) {
+        int activePhone = TelephonyManager.getDefault().getPhoneType();
+        TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ?
+            com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false) :
+            com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false);
+
+        // TODO(cleanup): The code here could be rolled into the logic
+        // below cleanly if these MAX_* constants were defined more
+        // flexibly...
+
+        int limit;
+        if (ted.msgCount > 1) {
+            limit = (ted.codeUnitSize == ENCODING_7BIT) ?
+                MAX_USER_DATA_SEPTETS_WITH_HEADER : MAX_USER_DATA_BYTES_WITH_HEADER;
         } else {
-            int octets = msgBody.length() * 2;
-            ret[1] = msgBody.length();
-            if (octets > MAX_USER_DATA_BYTES) {
-                ret[0] = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1;
-                ret[2] = (MAX_USER_DATA_BYTES_WITH_HEADER
-                            - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2;
-            } else {
-                ret[0] = 1;
-                ret[2] = (MAX_USER_DATA_BYTES - octets)/2;
-            }
-            ret[3] = ENCODING_16BIT;
+            limit = (ted.codeUnitSize == ENCODING_7BIT) ?
+                MAX_USER_DATA_SEPTETS : MAX_USER_DATA_BYTES;
         }
 
-        return ret;
+        int pos = 0;  // Index in code units.
+        int textLen = text.length();
+        ArrayList<String> result = new ArrayList<String>(ted.msgCount);
+        while (pos < textLen) {
+            int nextPos = 0;  // Counts code units.
+            if (ted.codeUnitSize == ENCODING_7BIT) {
+                if (PHONE_TYPE_CDMA == activePhone) {
+                    nextPos = pos + Math.min(limit, textLen - pos);
+                } else {
+                    nextPos = GsmAlphabet.findGsmSeptetLimitIndex(text, pos, limit);
+                }
+            } else {  // Assume unicode.
+                nextPos = pos + Math.min(limit / 2, textLen - pos);
+            }
+            if ((nextPos <= pos) || (nextPos > textLen)) {
+                Log.e(LOG_TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " +
+                          nextPos + " >= " + textLen + ")");
+                break;
+            }
+            result.add(text.substring(pos, nextPos));
+            pos = nextPos;
+        }
+        return result;
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index 8e2941b..e8095e1 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -576,52 +576,6 @@
         return size;
     }
 
-    /**
-     * Returns the index into <code>s</code> of the first character
-     * after <code>limit</code> octets have been reached, starting at
-     * index <code>start</code>.  This is used when dividing messages
-     * in UCS2 encoding into units within the SMS message size limit.
-     *
-     * @param s source string
-     * @param start index of where to start counting septets
-     * @param limit maximum septets to include,
-     *   e.g. <code>MAX_USER_DATA_BYTES</code>
-     * @return index of first character that won't fit, or the length
-     *   of the entire string if everything fits
-     */
-    public static int
-    findUCS2LimitIndex(String s, int start, int limit) {
-        int numCharToBeEncoded = s.length() - start;
-        return ((numCharToBeEncoded*2 > limit)? limit/2: numCharToBeEncoded) + start;
-    }
-
-    /**
-     * Returns the index into <code>s</code> of the first character
-     * after <code>limit</code> septets/octets have been reached
-     * according to the <code>encodingType</code>, starting at
-     * index <code>start</code>.  This is used when dividing messages
-     * units within the SMS message size limit.
-     *
-     * @param s source string
-     * @param start index of where to start counting septets
-     * @param limit maximum septets to include,
-     *   e.g. <code>MAX_USER_DATA_BYTES</code>
-     * @return index of first character that won't fit, or the length
-     *   of the entire string if everything fits
-     */
-    public static int
-    findLimitIndex(String s, int start, int limit, int encodingType) throws EncodeException {
-        if (encodingType == SmsMessage.ENCODING_7BIT) {
-            return findGsmSeptetLimitIndex(s, start, limit);
-        }
-        else if (encodingType == SmsMessage.ENCODING_16BIT) {
-            return findUCS2LimitIndex(s, start, limit);
-        }
-        else {
-            throw new EncodeException("Unsupported encoding type: " + encodingType);
-        }
-    }
-
     // Set in the static initializer
     private static int sGsmSpaceChar;
 
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 07fc7c6..9f780c9 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1268,7 +1268,11 @@
         rr.mp.writeString(user);
         rr.mp.writeString(password);
         //TODO(): Add to the APN database, AuthType is set to CHAP/PAP
-        rr.mp.writeString("3");
+        // 0 => Neither PAP nor CHAP will be performed, 3 => PAP / CHAP will be performed.
+        if (user != null)
+            rr.mp.writeString("3");
+        else
+            rr.mp.writeString("0");
 
         if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " "
                 + apn);
@@ -2063,13 +2067,13 @@
  | sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: ret = \2(p); break;/'
              */
             case RIL_REQUEST_GET_SIM_STATUS: ret =  responseIccCardStatus(p); break;
-            case RIL_REQUEST_ENTER_SIM_PIN: ret =  responseVoid(p); break;
-            case RIL_REQUEST_ENTER_SIM_PUK: ret =  responseVoid(p); break;
-            case RIL_REQUEST_ENTER_SIM_PIN2: ret =  responseVoid(p); break;
-            case RIL_REQUEST_ENTER_SIM_PUK2: ret =  responseVoid(p); break;
-            case RIL_REQUEST_CHANGE_SIM_PIN: ret =  responseVoid(p); break;
-            case RIL_REQUEST_CHANGE_SIM_PIN2: ret =  responseVoid(p); break;
-            case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: ret =  responseVoid(p); break;
+            case RIL_REQUEST_ENTER_SIM_PIN: ret =  responseInts(p); break;
+            case RIL_REQUEST_ENTER_SIM_PUK: ret =  responseInts(p); break;
+            case RIL_REQUEST_ENTER_SIM_PIN2: ret =  responseInts(p); break;
+            case RIL_REQUEST_ENTER_SIM_PUK2: ret =  responseInts(p); break;
+            case RIL_REQUEST_CHANGE_SIM_PIN: ret =  responseInts(p); break;
+            case RIL_REQUEST_CHANGE_SIM_PIN2: ret =  responseInts(p); break;
+            case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: ret =  responseInts(p); break;
             case RIL_REQUEST_GET_CURRENT_CALLS: ret =  responseCallList(p); break;
             case RIL_REQUEST_DIAL: ret =  responseVoid(p); break;
             case RIL_REQUEST_GET_IMSI: ret =  responseString(p); break;
@@ -2104,7 +2108,7 @@
             case RIL_REQUEST_ANSWER: ret =  responseVoid(p); break;
             case RIL_REQUEST_DEACTIVATE_DATA_CALL: ret =  responseVoid(p); break;
             case RIL_REQUEST_QUERY_FACILITY_LOCK: ret =  responseInts(p); break;
-            case RIL_REQUEST_SET_FACILITY_LOCK: ret =  responseVoid(p); break;
+            case RIL_REQUEST_SET_FACILITY_LOCK: ret =  responseInts(p); break;
             case RIL_REQUEST_CHANGE_BARRING_PASSWORD: ret =  responseVoid(p); break;
             case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: ret =  responseInts(p); break;
             case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: ret =  responseVoid(p); break;
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index 4d32c35..3c7dd45 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -86,6 +86,38 @@
     /** TP-Message-Reference - Message Reference of sent message. @hide */
     public int messageRef;
 
+    /**
+     * For a specific text string, this object describes protocol
+     * properties of encoding it for transmission as message user
+     * data.
+     */
+    public static class TextEncodingDetails {
+        /**
+         *The number of SMS's required to encode the text.
+         */
+        public int msgCount;
+
+        /**
+         * The number of code units consumed so far, where code units
+         * are basically characters in the encoding -- for example,
+         * septets for the standard ASCII and GSM encodings, and 16
+         * bits for Unicode.
+         */
+        public int codeUnitCount;
+
+        /**
+         * How many code units are still available without spilling
+         * into an additional message.
+         */
+        public int codeUnitsRemaining;
+
+        /**
+         * The encoding code unit size (specified using
+         * android.telephony.SmsMessage ENCODING_*).
+         */
+        public int codeUnitSize;
+    }
+
     public static abstract class SubmitPduBase  {
         public byte[] encodedScAddress; // Null if not applicable.
         public byte[] encodedMessage;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index 79e1cd6..2b4a700 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -34,6 +34,7 @@
 import com.android.internal.telephony.SMSDispatcher;
 import com.android.internal.telephony.cdma.SmsMessage;
 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
+import com.android.internal.telephony.cdma.sms.UserData;
 import com.android.internal.util.HexDump;
 
 import java.io.ByteArrayOutputStream;
@@ -302,8 +303,12 @@
                 deliveryIntent = deliveryIntents.get(i);
             }
 
-            SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(scAddr, destAddr,
-                    parts.get(i), deliveryIntent != null, smsHeader);
+            UserData uData = new UserData();
+            uData.payloadStr = parts.get(i);
+            uData.userDataHeader = smsHeader;
+
+            SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(destAddr,
+                    uData, deliveryIntent != null);
 
             sendSubmitPdu(submitPdu, sentIntent, deliveryIntent);
         }
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index bbdd0dd..63d2c47 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -357,14 +357,18 @@
     }
 
     /**
-     * Calculate the number of septets needed to encode the message.
+     * Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
      *
-     * @param messageBody the message to encode
-     * @param force ignore (but still count) illegal characters if true
-     * @return septet count, or -1 on failure
+     * @param destAddr the address of the destination for the message
+     * @param userDara the data for the message
+     * @param statusReportRequested Indicates whether a report is requested for this message.
+     * @return a <code>SubmitPdu</code> containing the encoded SC
+     *         address, if applicable, and the encoded message.
+     *         Returns null on encode error.
      */
-    public static int calc7bitEncodedLength(CharSequence msgBody, boolean force) {
-        return BearerData.calc7bitEncodedLength(msgBody.toString(), force);
+    public static SubmitPdu getSubmitPdu(String destAddr, UserData userData,
+            boolean statusReportRequested) {
+        return privateGetSubmitPdu(destAddr, statusReportRequested, userData);
     }
 
     /**
@@ -442,6 +446,18 @@
     }
 
     /**
+     * Calculate the number of septets needed to encode the message.
+     *
+     * @param messageBody the message to encode
+     * @param use7bitOnly ignore (but still count) illegal characters if true
+     * @return TextEncodingDetails
+     */
+    public static TextEncodingDetails calculateLength(CharSequence messageBody,
+            boolean use7bitOnly) {
+        return BearerData.calcTextEncodingDetails(messageBody.toString(), use7bitOnly);
+    }
+
+    /**
      * Returns the teleservice type of the message.
      * @return the teleservice:
      *  {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_NOT_SET},
@@ -627,12 +643,15 @@
         bearerData.userData = userData;
         bearerData.hasUserDataHeader = (userData.userDataHeader != null);
 
+        int teleservice = bearerData.hasUserDataHeader ?
+                SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT;
+
         byte[] encodedBearerData = BearerData.encode(bearerData);
         if (encodedBearerData == null) return null;
 
         SmsEnvelope envelope = new SmsEnvelope();
         envelope.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
-        envelope.teleService = SmsEnvelope.TELESERVICE_WMT;
+        envelope.teleService = teleservice;
         envelope.destAddress = destAddr;
         envelope.bearerReply = RETURN_ACK;
         envelope.bearerData = encodedBearerData;
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index 3c45aa4..a835dee 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony.cdma.sms;
 
 import android.util.Log;
+import android.util.SparseIntArray;
 
 import android.telephony.SmsMessage;
 
@@ -26,6 +27,7 @@
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.cdma.sms.UserData;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
 
 import com.android.internal.util.HexDump;
 import com.android.internal.util.BitwiseInputStream;
@@ -35,7 +37,7 @@
 /**
  * An object to encode and decode CDMA SMS bearer data.
  */
-public final class BearerData{
+public final class BearerData {
     private final static String LOG_TAG = "SMS";
 
     /**
@@ -385,56 +387,61 @@
         outStream.skip(3);
     }
 
-    private static class SeptetData {
-        byte data[];
-        int septetCount;
-
-        SeptetData(byte[] data, int septetCount) {
-            this.data = data;
-            this.septetCount = septetCount;
-        }
-    }
-
-    private static SeptetData encode7bitAscii(String msg, boolean force)
-        throws CodingException
-    {
-        try {
-            BitwiseOutputStream outStream = new BitwiseOutputStream(msg.length());
-            byte[] expandedData = msg.getBytes("US-ASCII");
-            for (int i = 0; i < expandedData.length; i++) {
-                int charCode = expandedData[i];
-                // Test ourselves for ASCII membership, since Java seems not to care.
-                if ((charCode < UserData.PRINTABLE_ASCII_MIN_INDEX) ||
-                        (charCode > UserData.PRINTABLE_ASCII_MAX_INDEX)) {
-                    if (force) {
-                        outStream.write(7, UserData.UNENCODABLE_7_BIT_CHAR);
-                    } else {
-                        throw new CodingException("illegal ASCII code (" + charCode + ")");
-                    }
-                } else {
-                    outStream.write(7, expandedData[i]);
-                }
+    private static int countAsciiSeptets(CharSequence msg, boolean force) {
+        int msgLen = msg.length();
+        if (force) return msgLen;
+        for (int i = 0; i < msgLen; i++) {
+            if (UserData.charToAscii.get(msg.charAt(i), -1) == -1) {
+                return -1;
             }
-            return new SeptetData(outStream.toByteArray(), expandedData.length);
-        } catch (java.io.UnsupportedEncodingException ex) {
-            throw new CodingException("7bit ASCII encode failed: " + ex);
-        } catch (BitwiseOutputStream.AccessException ex) {
-            throw new CodingException("7bit ASCII encode failed: " + ex);
         }
+        return msgLen;
     }
 
     /**
-     * Calculate the number of septets needed to encode the message.
+     * Calculate the message text encoding length, fragmentation, and other details.
      *
      * @param force ignore (but still count) illegal characters if true
      * @return septet count, or -1 on failure
      */
-    public static int calc7bitEncodedLength(String msg, boolean force) {
+    public static TextEncodingDetails calcTextEncodingDetails(CharSequence msg,
+            boolean force7BitEncoding) {
+        TextEncodingDetails ted;
+        int septets = countAsciiSeptets(msg, force7BitEncoding);
+        if (septets != -1 && septets <= SmsMessage.MAX_USER_DATA_SEPTETS) {
+            ted = new TextEncodingDetails();
+            ted.msgCount = 1;
+            ted.codeUnitCount = septets;
+            ted.codeUnitsRemaining = SmsMessage.MAX_USER_DATA_SEPTETS - septets;
+            ted.codeUnitSize = SmsMessage.ENCODING_7BIT;
+        } else {
+            ted = com.android.internal.telephony.gsm.SmsMessage.calculateLength(
+                    msg, force7BitEncoding);
+        }
+        return ted;
+    }
+
+    private static byte[] encode7bitAscii(String msg, boolean force)
+        throws CodingException
+    {
         try {
-            SeptetData data = encode7bitAscii(msg, force);
-            return data.septetCount;
-        } catch (CodingException ex) {
-            return -1;
+            BitwiseOutputStream outStream = new BitwiseOutputStream(msg.length());
+            int msgLen = msg.length();
+            for (int i = 0; i < msgLen; i++) {
+                int charCode = UserData.charToAscii.get(msg.charAt(i), -1);
+                if (charCode == -1) {
+                    if (force) {
+                        outStream.write(7, UserData.UNENCODABLE_7_BIT_CHAR);
+                    } else {
+                        throw new CodingException("cannot ASCII encode (" + msg.charAt(i) + ")");
+                    }
+                } else {
+                    outStream.write(7, charCode);
+                }
+            }
+            return outStream.toByteArray();
+        } catch (BitwiseOutputStream.AccessException ex) {
+            throw new CodingException("7bit ASCII encode failed: " + ex);
         }
     }
 
@@ -452,8 +459,10 @@
         throws CodingException
     {
         try {
-            /**
-             * TODO(cleanup): find some way to do this without the copy.
+            /*
+             * TODO(cleanup): It would be nice if GsmAlphabet provided
+             * an option to produce just the data without prepending
+             * the length.
              */
             byte []fullData = GsmAlphabet.stringToGsm7BitPacked(msg);
             byte []data = new byte[fullData.length - 1];
@@ -470,54 +479,65 @@
         throws CodingException
     {
         byte[] headerData = null;
+        // TODO: if there is a header, meaning EMS mode, we probably
+        // also want the total UD length prior to the UDH length...
         if (uData.userDataHeader != null) headerData = SmsHeader.toByteArray(uData.userDataHeader);
         int headerDataLen = (headerData == null) ? 0 : headerData.length + 1;  // + length octet
 
         byte[] payloadData;
+        int codeUnitCount;
         if (uData.msgEncodingSet) {
             if (uData.msgEncoding == UserData.ENCODING_OCTET) {
                 if (uData.payload == null) {
                     Log.e(LOG_TAG, "user data with octet encoding but null payload");
-                    // TODO(code_review): reasonable for fail case? or maybe bail on encoding?
                     payloadData = new byte[0];
+                    codeUnitCount = 0;
                 } else {
                     payloadData = uData.payload;
+                    codeUnitCount = uData.payload.length;
                 }
             } else {
                 if (uData.payloadStr == null) {
                     Log.e(LOG_TAG, "non-octet user data with null payloadStr");
-                    // TODO(code_review): reasonable for fail case? or maybe bail on encoding?
                     uData.payloadStr = "";
                 }
                 if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
                     payloadData = encode7bitGsm(uData.payloadStr);
+                    codeUnitCount = (payloadData.length * 8) / 7;
                 } else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) {
-                    SeptetData septetData = encode7bitAscii(uData.payloadStr, true);
-                    payloadData = septetData.data;
+                    payloadData = encode7bitAscii(uData.payloadStr, true);
+                    codeUnitCount = uData.payloadStr.length();
                 } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
                     payloadData = encodeUtf16(uData.payloadStr);
+                    codeUnitCount = uData.payloadStr.length();
                 } else {
                     throw new CodingException("unsupported user data encoding (" +
                                               uData.msgEncoding + ")");
                 }
-                uData.numFields = uData.payloadStr.length();
             }
         } else {
             if (uData.payloadStr == null) {
                 Log.e(LOG_TAG, "user data with null payloadStr");
-                // TODO(code_review): reasonable for fail case? or maybe bail on encoding?
                 uData.payloadStr = "";
             }
             try {
-                SeptetData septetData = encode7bitAscii(uData.payloadStr, false);
-                payloadData = septetData.data;
-                uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
+                if (headerData == null) {
+                    payloadData = encode7bitAscii(uData.payloadStr, false);
+                    codeUnitCount = uData.payloadStr.length();
+                    uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
+                } else {
+                    // If there is a header, we are in EMS mode, in
+                    // which case we use GSM encodings.
+                    payloadData = encode7bitGsm(uData.payloadStr);
+                    codeUnitCount = (payloadData.length * 8) / 7;
+                    uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
+                }
             } catch (CodingException ex) {
                 payloadData = encodeUtf16(uData.payloadStr);
+                codeUnitCount = uData.payloadStr.length();
                 uData.msgEncoding = UserData.ENCODING_UNICODE_16;
             }
             uData.msgEncodingSet = true;
-            uData.numFields = uData.payloadStr.length();
         }
 
         int totalLength = payloadData.length + headerDataLen;
@@ -526,6 +546,7 @@
                                       " > " + SmsMessage.MAX_USER_DATA_BYTES + " bytes)");
         }
 
+        uData.numFields = codeUnitCount;
         uData.payload = new byte[totalLength];
         if (headerData != null) {
             uData.payload[0] = (byte)headerData.length;
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
index 8d4e769..d8a48cc 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.telephony.cdma.sms;
 
+import android.util.SparseIntArray;
+
 import com.android.internal.telephony.SmsHeader;
 import com.android.internal.util.HexDump;
 
@@ -40,6 +42,10 @@
     /**
      * IA5 data encoding character mappings.
      * (See CCITT Rec. T.50 Tables 1 and 3)
+     *
+     * Note this mapping is the the same as for printable ASCII
+     * characters, with a 0x20 offset, meaning that the ASCII SPACE
+     * character occurs with code 0x20.
      */
     public static final char[] IA5_MAP = {
         ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
@@ -61,7 +67,16 @@
      * Only elements between these indices in the ASCII table are printable.
      */
     public static final int PRINTABLE_ASCII_MIN_INDEX = 0x20;
-    public static final int PRINTABLE_ASCII_MAX_INDEX = 0x7F;
+    public static final int ASCII_LF_INDEX = 0x0A;
+    public static final int ASCII_CR_INDEX = 0x0D;
+    public static final SparseIntArray charToAscii = new SparseIntArray();
+    static {
+        for (int i = 0; i < IA5_MAP.length; i++) {
+            charToAscii.put(IA5_MAP[i], PRINTABLE_ASCII_MIN_INDEX + i);
+        }
+        charToAscii.put('\r', ASCII_LF_INDEX);
+        charToAscii.put('\n', ASCII_CR_INDEX);
+    }
 
     /**
      * Mapping for IA5 values less than 32 are flow control signals
diff --git a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
index 278beef..55e5adc 100644
--- a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
@@ -58,18 +58,9 @@
     private String pdp_name;
     private ApnSetting apn;
 
-    // dataLink is only used to support pppd link
-    private DataLink dataLink;
-
     //***** Constructor
     PdpConnection(GSMPhone phone) {
         super(phone);
-        this.dataLink = null;
-
-        if (SystemProperties.get("ro.radio.use-ppp","no").equals("yes")) {
-            dataLink = new PppLink((GsmDataConnectionTracker) phone.mDataConnection, phone);
-            dataLink.setOnLinkChange(this, EVENT_LINK_STATE_CHANGED, null);
-        }
     }
 
     /**
@@ -97,10 +88,6 @@
     }
 
     private void tearDownData(Message msg) {
-        if (dataLink != null) {
-            dataLink.disconnect();
-        }
-
         if (phone.mCM.getRadioState().isOn()) {
             phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg));
         }
@@ -313,11 +300,7 @@
                     }
                 }
 
-                if (dataLink != null) {
-                    dataLink.connect();
-                } else {
-                    onLinkStateChanged(DataLink.LinkState.LINK_UP);
-                }
+                onLinkStateChanged(DataLink.LinkState.LINK_UP);
 
                 if (DBG) log("PDP setup on cid = " + cid);
             }
diff --git a/telephony/java/com/android/internal/telephony/gsm/PppLink.java b/telephony/java/com/android/internal/telephony/gsm/PppLink.java
deleted file mode 100644
index 9627696..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/PppLink.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2006 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 com.android.internal.telephony.gsm;
-
-import android.database.Cursor;
-import android.os.Message;
-import android.os.SystemProperties;
-import android.os.SystemService;
-import android.util.Log;
-
-import com.android.internal.telephony.DataLink;
-import com.android.internal.telephony.DataConnectionTracker.State;
-import com.android.internal.telephony.PhoneBase;
-import com.android.internal.util.ArrayUtils;
-
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-/**
- * Represents a PPP link.
- *
- * Ideally this would be managed by the RIL implementation, but
- * we currently have implementations where this is not the case.
- *
- * {@hide}
- */
-final class PppLink extends DataLink {
-    private static final String LOG_TAG = "GSM";
-
-    static final String PATH_PPP_OPERSTATE = "/sys/class/net/ppp0/operstate";
-    static final String SERVICE_PPPD_GPRS = "pppd_gprs";
-    static final String PROPERTY_PPPD_EXIT_CODE = "net.gprs.ppp-exit";
-    static final int POLL_SYSFS_MILLIS = 5 * 1000;
-    static final int EVENT_POLL_DATA_CONNECTION = 2;
-    static final int EVENT_PPP_OPERSTATE_CHANGED = 8;
-    static final int EVENT_PPP_PIDFILE_CHANGED = 9;
-
-    static final byte[] UP_ASCII_STRING = new byte[] {
-        'u' & 0xff,
-        'p' & 0xff,
-    };
-    static final byte[] DOWN_ASCII_STRING = new byte[] {
-        'd' & 0xff,
-        'o' & 0xff,
-        'w' & 0xff,
-        'n' & 0xff,
-    };
-    static final byte[] UNKNOWN_ASCII_STRING = new byte[] {
-        'u' & 0xff,
-        'n' & 0xff,
-        'k' & 0xff,
-        'n' & 0xff,
-        'o' & 0xff,
-        'w' & 0xff,
-        'n' & 0xff,
-    };
-    private final byte[] mCheckPPPBuffer = new byte[32];
-
-    private PhoneBase phone;
-
-    int lastPppdExitCode = EXIT_OK;
-
-
-    PppLink(GsmDataConnectionTracker dc, GSMPhone p) {
-        super(dc);
-        this.phone = p;
-    }
-
-    public void connect() {
-        // Clear any previous exit code
-        SystemProperties.set(PROPERTY_PPPD_EXIT_CODE, "");
-        SystemService.start(SERVICE_PPPD_GPRS);
-        removeMessages(EVENT_POLL_DATA_CONNECTION);
-        Message poll = obtainMessage();
-        poll.what = EVENT_POLL_DATA_CONNECTION;
-        sendMessageDelayed(poll, POLL_SYSFS_MILLIS);
-    }
-
-    public void disconnect() {
-        SystemService.stop(SERVICE_PPPD_GPRS);
-    }
-
-    public int getLastLinkExitCode() {
-        return lastPppdExitCode;
-    }
-
-    public void setPasswordInfo(Cursor cursor) {
-        StringBuilder builder = new StringBuilder();
-        FileOutputStream output = null;
-
-        try {
-            output = new FileOutputStream("/etc/ppp/pap-secrets");
-            if (cursor.moveToFirst()) {
-                do {
-                    builder.append(cursor.getString(cursor.getColumnIndex("user")));
-                    builder.append(" ");
-                    builder.append(cursor.getString(cursor.getColumnIndex("server")));
-                    builder.append(" ");
-                    builder.append(cursor.getString(cursor.getColumnIndex("password")));
-                    builder.append("\n");
-                } while (cursor.moveToNext());
-            }
-
-            output.write(builder.toString().getBytes());
-        } catch (java.io.IOException e) {
-            Log.e(LOG_TAG, "Could not create '/etc/ppp/pap-secrets'", e);
-        } finally {
-            try {
-                if (output != null) output.close();
-            } catch (java.io.IOException e) {
-                Log.e(LOG_TAG, "Error closing '/etc/ppp/pap-secrets'", e);
-            }
-        }
-    }
-
-    public void handleMessage (Message msg) {
-
-        switch (msg.what) {
-
-            case EVENT_POLL_DATA_CONNECTION:
-                checkPPP();
-
-                // keep polling in case interface goes down
-                if (dataConnection.getState() != State.IDLE) {
-                    Message poll = obtainMessage();
-                    poll.what = EVENT_POLL_DATA_CONNECTION;
-                    sendMessageDelayed(poll, POLL_SYSFS_MILLIS);
-                }
-                break;
-        }
-    }
-
-    private void checkPPP() {
-        boolean connecting = (dataConnection.getState() == State.CONNECTING);
-
-        try {
-            RandomAccessFile file = new RandomAccessFile(PATH_PPP_OPERSTATE, "r");
-            file.read(mCheckPPPBuffer);
-            file.close();
-
-            // Unfortunately, we're currently seeing operstate
-            // "unknown" where one might otherwise expect "up"
-            if (ArrayUtils.equals(mCheckPPPBuffer, UP_ASCII_STRING, UP_ASCII_STRING.length)
-                    || ArrayUtils.equals(mCheckPPPBuffer, UNKNOWN_ASCII_STRING,
-                    UNKNOWN_ASCII_STRING.length)
-                    && dataConnection.getState() == State.CONNECTING) {
-
-                Log.i(LOG_TAG,
-                "found ppp interface. Notifying GPRS connected");
-
-                if (mLinkChangeRegistrant != null) {
-                    mLinkChangeRegistrant.notifyResult(LinkState.LINK_UP);
-                }
-
-                connecting = false;
-            } else if (dataConnection.getState() == State.CONNECTED
-                    && ArrayUtils.equals(mCheckPPPBuffer, DOWN_ASCII_STRING,
-                    DOWN_ASCII_STRING.length)) {
-
-                Log.i(LOG_TAG,
-                "ppp interface went down. Reconnecting...");
-
-                if (mLinkChangeRegistrant != null) {
-                    mLinkChangeRegistrant.notifyResult(LinkState.LINK_DOWN);
-                }
-            }
-        } catch (IOException ex) {
-            if (! (ex instanceof FileNotFoundException)) {
-                Log.i(LOG_TAG, "Poll ppp0 ex " + ex.toString());
-            }
-
-            if (dataConnection.getState() == State.CONNECTED &&
-                    mLinkChangeRegistrant != null) {
-                mLinkChangeRegistrant.notifyResult(LinkState.LINK_DOWN);
-            }
-        }
-
-        // CONNECTING means pppd has started but negotiation is not complete
-        // If we're still CONNECTING here, check to see if pppd has
-        // already exited
-        if (connecting) {
-            String exitCode;
-
-            exitCode = SystemProperties.get(PROPERTY_PPPD_EXIT_CODE, "");
-
-            if (!exitCode.equals("")) {
-                // pppd has exited. Let's figure out why
-                lastPppdExitCode = Integer.parseInt(exitCode);
-
-                Log.d(LOG_TAG,"pppd exited with " + exitCode);
-
-                if (mLinkChangeRegistrant != null) {
-                    mLinkChangeRegistrant.notifyResult(LinkState.LINK_EXITED);
-                }
-            }
-        }
-
-    }
-
-    protected void log(String s) {
-        Log.d(LOG_TAG, "[PppLink] " + s);
-    }
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index a15bbdf..f1207e4 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -26,6 +26,7 @@
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.SmsMessageBase;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
 
 import java.io.ByteArrayOutputStream;
 import java.io.UnsupportedEncodingException;
@@ -742,17 +743,39 @@
     /**
      * Calculate the number of septets needed to encode the message.
      *
-     * @param messageBody the message to encode
-     * @param force ignore (but still count) illegal characters if true
-     * @return septet count, or -1 on failure
+     * @param msgBody the message to encode
+     * @param use7bitOnly ignore (but still count) illegal characters if true
+     * @return TextEncodingDetails
      */
-    public static int calc7bitEncodedLength(CharSequence messageBody, boolean force) {
+    public static TextEncodingDetails calculateLength(CharSequence msgBody,
+            boolean use7bitOnly) {
+        TextEncodingDetails ted = new TextEncodingDetails();
         try {
-            return GsmAlphabet.countGsmSeptets(messageBody, !force);
+            int septets = GsmAlphabet.countGsmSeptets(msgBody, !use7bitOnly);
+            ted.codeUnitCount = septets;
+            if (septets > MAX_USER_DATA_SEPTETS) {
+                ted.msgCount = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1;
+                ted.codeUnitsRemaining = MAX_USER_DATA_SEPTETS_WITH_HEADER
+                    - (septets % MAX_USER_DATA_SEPTETS_WITH_HEADER);
+            } else {
+                ted.msgCount = 1;
+                ted.codeUnitsRemaining = MAX_USER_DATA_SEPTETS - septets;
+            }
+            ted.codeUnitSize = ENCODING_7BIT;
         } catch (EncodeException ex) {
-            /* Just fall through to the -1 error result below. */
+            int octets = msgBody.length() * 2;
+            ted.codeUnitCount = msgBody.length();
+            if (octets > MAX_USER_DATA_BYTES) {
+                ted.msgCount = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1;
+                ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES_WITH_HEADER
+                          - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2;
+            } else {
+                ted.msgCount = 1;
+                ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES - octets)/2;
+            }
+            ted.codeUnitSize = ENCODING_16BIT;
         }
-        return -1;
+        return ted;
     }
 
     /** {@inheritDoc} */
diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/android/test/mock/MockContext.java
index 9e0cf2c..efc4880 100644
--- a/test-runner/android/test/mock/MockContext.java
+++ b/test-runner/android/test/mock/MockContext.java
@@ -24,6 +24,7 @@
 import android.content.BroadcastReceiver;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
@@ -100,6 +101,11 @@
     }
 
     @Override
+    public ApplicationInfo getApplicationInfo() {
+        throw new UnsupportedOperationException();
+    }
+    
+    @Override
     public String getPackageResourcePath() {
         throw new UnsupportedOperationException();
     }
diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java
index a9c2657..63a177e 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/android/test/mock/MockPackageManager.java
@@ -16,7 +16,6 @@
 
 package android.test.mock;
 
-import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -324,21 +323,12 @@
             long idealStorageSize, IPackageDataObserver observer) {
         throw new UnsupportedOperationException();
     }
-    
-    /**
-     * @hide - to match hiding in superclass
-     */
-    @Override
-    public void freeStorage(
-            long idealStorageSize, PendingIntent onFinishedIntent) {
-        throw new UnsupportedOperationException();
-    }
 
     /**
      * @hide - to match hiding in superclass
      */
     @Override
-    public void freeStorageWithIntent(
+    public void freeStorage(
             long idealStorageSize, IntentSender pi) {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java b/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
index 3daa8ab..fb1b9ad 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
@@ -507,7 +507,7 @@
         try {
             // Spin lock waiting for call back
             synchronized(r) {
-                getPm().freeStorage(idealStorageSize, pi);
+                getPm().freeStorage(idealStorageSize, pi.getIntentSender());
                 long waitTime = 0;
                 while(!r.isDone() && (waitTime < MAX_WAIT_TIME)) {
                     r.wait(WAIT_TIME_INCR);
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
index f03a779..c4f1ab6 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
@@ -126,26 +126,6 @@
     }
     
     /**
-     * The goal of this test is to confirm that we can *only* obtain a search manager
-     * interface from an Activity context.
-     */
-    @MediumTest
-    public void testSearchManagerContextRestrictions() {
-        SearchManager searchManager1 = (SearchManager)
-                mContext.getSystemService(Context.SEARCH_SERVICE);
-        assertNotNull(searchManager1);
-        
-        Context applicationContext = mContext.getApplicationContext();
-        // this should fail, because you can't get a SearchManager from a non-Activity context
-        try {
-            applicationContext.getSystemService(Context.SEARCH_SERVICE);
-            assertFalse("Shouldn't retrieve SearchManager from a non-Activity context", true);
-        } catch (AndroidRuntimeException e) {
-            // happy here - we should catch this.
-        }
-    }
-    
-    /**
      * The goal of this test is to confirm that we can obtain
      * a search manager at any time, and that for any given context,
      * it is a singleton.
@@ -163,17 +143,19 @@
 
     @MediumTest
     public void testSearchables() {
+        SearchManager searchManager = (SearchManager)
+                mContext.getSystemService(Context.SEARCH_SERVICE);
         SearchableInfo si;
 
-        si = SearchManager.getSearchableInfo(SEARCHABLE_ACTIVITY, false);
+        si = searchManager.getSearchableInfo(SEARCHABLE_ACTIVITY, false);
         assertNotNull(si);
-        assertFalse(SearchManager.isDefaultSearchable(si));
-        si = SearchManager.getSearchableInfo(SEARCHABLE_ACTIVITY, true);
+        assertFalse(searchManager.isDefaultSearchable(si));
+        si = searchManager.getSearchableInfo(SEARCHABLE_ACTIVITY, true);
         assertNotNull(si);
-        assertTrue(SearchManager.isDefaultSearchable(si));
-        si = SearchManager.getSearchableInfo(null, true);
+        assertTrue(searchManager.isDefaultSearchable(si));
+        si = searchManager.getSearchableInfo(null, true);
         assertNotNull(si);
-        assertTrue(SearchManager.isDefaultSearchable(si));
+        assertTrue(searchManager.isDefaultSearchable(si));
     }
 
     /**
diff --git a/tests/DumpRenderTree/assets/run_layout_tests.py b/tests/DumpRenderTree/assets/run_layout_tests.py
index 50ccb24..49165d0 100755
--- a/tests/DumpRenderTree/assets/run_layout_tests.py
+++ b/tests/DumpRenderTree/assets/run_layout_tests.py
@@ -131,7 +131,7 @@
     result_file_name = "layout_tests_" + f + ".txt"
     DiffResults(f, os.path.join(results_dir, result_file_name),
                 os.path.join(ref_dir, result_file_name), diff_result,
-                False, files != "passed")
+                False, f != "passed")
   logging.info("Detailed diffs are in " + diff_result)
 
 def main(options, args):
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
index a389461..39ce1f2 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
@@ -18,6 +18,7 @@
 
 import android.os.Handler;
 import android.os.Message;
+import android.webkit.WebStorage;
 
 import java.util.HashMap;
 
@@ -25,7 +26,7 @@
     
     private EventSender mEventSender;
     private LayoutTestController mLayoutTestController;
-    
+
     private static final int EVENT_DOM_LOG = 1;
     private static final int EVENT_FIRE_KBD = 2;
     private static final int EVENT_KEY_DOWN_1 = 3;
@@ -57,6 +58,8 @@
     private static final int LAYOUT_SET_WINDOW_KEY = 38;
     private static final int LAYOUT_TEST_REPAINT = 39;
     private static final int LAYOUT_WAIT_UNTIL_DONE = 40;
+    private static final int LAYOUT_DUMP_DATABASE_CALLBACKS = 41;
+    private static final int LAYOUT_SET_CAN_OPEN_WINDOWS = 42;
     
     CallbackProxy(EventSender eventSender, 
             LayoutTestController layoutTestController) {
@@ -190,6 +193,14 @@
         case LAYOUT_WAIT_UNTIL_DONE:
             mLayoutTestController.waitUntilDone();
             break;
+
+        case LAYOUT_DUMP_DATABASE_CALLBACKS:
+            mLayoutTestController.dumpDatabaseCallbacks();
+            break;
+
+        case LAYOUT_SET_CAN_OPEN_WINDOWS:
+            mLayoutTestController.setCanOpenWindows();
+            break;
         }
     }
 
@@ -325,4 +336,20 @@
         obtainMessage(LAYOUT_WAIT_UNTIL_DONE).sendToTarget();
     }
 
+    public void dumpDatabaseCallbacks() {
+        obtainMessage(LAYOUT_DUMP_DATABASE_CALLBACKS).sendToTarget();
+    }
+
+    public void clearAllDatabases() {
+        WebStorage.getInstance().deleteAllDatabases();
+    }
+
+    public void setDatabaseQuota(long quota) {
+        WebStorage.getInstance().setQuotaForOrigin("file://", quota);
+    }
+
+    public void setCanOpenWindows() {
+        obtainMessage(LAYOUT_SET_CAN_OPEN_WINDOWS).sendToTarget();
+    }
+
 }
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 95a7ae3..ede5197 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -87,7 +87,15 @@
         "fast/regex/test1.html",
         "fast/regex/slow.html",
         // RegExp is too large, causing OOM
-        "fast/js/regexp-charclass-crash.html"
+        "fast/js/regexp-charclass-crash.html",
+        // The Android browser has no notion of private browsing.
+        "storage/private-browsing-readonly.html",
+        "storage/domstorage/localstorage/private-browsing-affects-storage.html",
+        "storage/domstorage/sessionstorage/private-browsing-affects-storage.html",
+        // Android layout tests are stored in "layout_tests". The following two
+        // tests expect "LayoutTests" in their output.
+        "storage/domstorage/localstorage/iframe-events.html",
+        "storage/domstorage/sessionstorage/iframe-events.html"
     };
     
     static void fillIgnoreResultSet() {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
index 6166dd0..e1d802a 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
@@ -58,5 +58,8 @@
     public void queueLoad(String Url, String frameTarget);
 
     public void setAcceptsEditing(boolean b);
-	
+
+    // For storage tests
+    public void dumpDatabaseCallbacks();
+    public void setCanOpenWindows();
 }
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 1ba291c..02658a1 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -31,6 +31,7 @@
 import android.webkit.SslErrorHandler;
 import android.webkit.WebChromeClient;
 import android.webkit.WebSettings;
+import android.webkit.WebStorage;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 import android.widget.LinearLayout;
@@ -38,6 +39,8 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.Vector;
 
 public class TestShellActivity extends Activity implements LayoutTestController {
@@ -90,52 +93,13 @@
         setContentView(contentView);
 
         mWebView = new WebView(this);
-        mWebView.getSettings().setJavaScriptEnabled(true);
-        mWebView.setWebChromeClient(mChromeClient);
-        mWebView.setWebViewClient(new WebViewClient(){
-
-            @Override
-            public void onPageFinished(WebView view, String url) {
-                Log.v(LOGTAG, "onPageFinished, url=" + url);
-                super.onPageFinished(view, url);
-            }
-
-            @Override
-            public void onPageStarted(WebView view, String url, Bitmap favicon) {
-                Log.v(LOGTAG, "onPageStarted, url=" + url);
-                super.onPageStarted(view, url, favicon);
-            }
-
-            @Override
-            public void onReceivedError(WebView view, int errorCode, String description,
-                    String failingUrl) {
-                Log.v(LOGTAG, "onReceivedError, errorCode=" + errorCode
-                        + ", desc=" + description + ", url=" + failingUrl);
-                super.onReceivedError(view, errorCode, description, failingUrl);
-            }
-
-            @Override
-            public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,
-                    String host, String realm) {
-                handler.cancel();
-            }
-
-            @Override
-            public void onReceivedSslError(WebView view, SslErrorHandler handler,
-                    SslError error) {
-                handler.proceed();
-            }
-
-        });
         mEventSender = new WebViewEventSender(mWebView);
         mCallbackProxy = new CallbackProxy(mEventSender, this);
 
-        mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController");
-        mWebView.addJavascriptInterface(mCallbackProxy, "eventSender");
+        setupWebViewForLayoutTests(mWebView, mCallbackProxy);
+
         contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 0.0f));
  
-        mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
-            
         mHandler = new AsyncHandler();
         
         Intent intent = getIntent();
@@ -217,6 +181,12 @@
             if (mDialogStrings != null)
                 os.write(mDialogStrings.toString().getBytes());
             mDialogStrings = null;
+            if (mDatabaseCallbackStrings != null)
+                os.write(mDatabaseCallbackStrings.toString().getBytes());
+            mDatabaseCallbackStrings = null;
+            if (mConsoleMessages != null)
+                os.write(mConsoleMessages.toString().getBytes());
+            mConsoleMessages = null;
             if (webkitData != null)
                 os.write(webkitData.getBytes());
             os.flush();
@@ -359,7 +329,52 @@
     public void testRepaint() {
         mWebView.invalidate();
     }
-    
+
+    public void dumpDatabaseCallbacks() {
+        Log.v(LOGTAG, "dumpDatabaseCallbacks called.");
+        mDumpDatabaseCallbacks = true;
+    }
+
+    public void setCanOpenWindows() {
+        Log.v(LOGTAG, "setCanOpenWindows called.");
+        mCanOpenWindows = true;
+    }
+
+    private final WebViewClient mViewClient = new WebViewClient(){
+        @Override
+        public void onPageFinished(WebView view, String url) {
+            Log.v(LOGTAG, "onPageFinished, url=" + url);
+            super.onPageFinished(view, url);
+        }
+
+        @Override
+        public void onPageStarted(WebView view, String url, Bitmap favicon) {
+            Log.v(LOGTAG, "onPageStarted, url=" + url);
+            super.onPageStarted(view, url, favicon);
+        }
+
+        @Override
+        public void onReceivedError(WebView view, int errorCode, String description,
+                String failingUrl) {
+            Log.v(LOGTAG, "onReceivedError, errorCode=" + errorCode
+                    + ", desc=" + description + ", url=" + failingUrl);
+            super.onReceivedError(view, errorCode, description, failingUrl);
+        }
+
+        @Override
+        public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,
+                String host, String realm) {
+            handler.cancel();
+        }
+
+        @Override
+        public void onReceivedSslError(WebView view, SslErrorHandler handler,
+                SslError error) {
+            handler.proceed();
+        }
+    };
+
+
     private final WebChromeClient mChromeClient = new WebChromeClient() {
         @Override
         public void onProgressChanged(WebView view, int newProgress) {
@@ -434,6 +449,72 @@
             result.confirm();
             return true;
         }
+
+        @Override
+        public void onExceededDatabaseQuota(String url_str,
+                String databaseIdentifier, long currentQuota,
+                WebStorage.QuotaUpdater callback) {
+            if (mDumpDatabaseCallbacks) {
+                if (mDatabaseCallbackStrings == null) {
+                    mDatabaseCallbackStrings = new StringBuffer();
+                }
+
+                String protocol = "";
+                String host = "";
+                int port = 0;
+
+                try {
+                    URL url = new URL(url_str);
+                    protocol = url.getProtocol();
+                    host = url.getHost();
+                    if (url.getPort() > -1) {
+                        port = url.getPort();
+                    }
+                } catch (MalformedURLException e) {}
+
+                String databaseCallbackString =
+                        "UI DELEGATE DATABASE CALLBACK: " +
+                        "exceededDatabaseQuotaForSecurityOrigin:{" + protocol +
+                        ", " + host + ", " + port + "} database:" +
+                        databaseIdentifier + "\n";
+                Log.v(LOGTAG, "LOG: "+databaseCallbackString);
+                mDatabaseCallbackStrings.append(databaseCallbackString);
+            }
+            // Give 5MB more quota.
+            callback.updateQuota(currentQuota + 1024 * 1024 * 5);
+        }
+
+        @Override
+        public void addMessageToConsole(String message, int lineNumber,
+                String sourceID) {
+            if (mConsoleMessages == null) {
+                mConsoleMessages = new StringBuffer();
+            }
+            String consoleMessage = "CONSOLE MESSAGE: line "
+                    + lineNumber +": "+ message +"\n";
+            mConsoleMessages.append(consoleMessage);
+            Log.v(LOGTAG, "LOG: "+consoleMessage);
+        }
+
+        @Override
+        public boolean onCreateWindow(WebView view, boolean dialog,
+                boolean userGesture, Message resultMsg) {
+            if (!mCanOpenWindows) {
+                return false;
+            }
+
+            // We never display the new window, just create the view and
+            // allow it's content to execute and be recorded by the test
+            // runner.
+
+            WebView newWindowView = new WebView(TestShellActivity.this);
+            setupWebViewForLayoutTests(newWindowView, mCallbackProxy);
+            WebView.WebViewTransport transport =
+                    (WebView.WebViewTransport) resultMsg.obj;
+            transport.setWebView(newWindowView);
+            resultMsg.sendToTarget();
+            return true;
+        }
     };
     
     private void resetTestStatus() {
@@ -442,9 +523,32 @@
         mTimedOut = false;
         mDumpTitleChanges = false;
         mRequestedWebKitData = false;
+        mDumpDatabaseCallbacks = false;
+        mCanOpenWindows = false;
         mEventSender.resetMouse();
     }
-    
+
+    private void setupWebViewForLayoutTests(WebView webview, CallbackProxy callbackProxy) {
+        if (webview == null) {
+            return;
+        }
+
+        WebSettings settings = webview.getSettings();
+        settings.setJavaScriptEnabled(true);
+        settings.setJavaScriptCanOpenWindowsAutomatically(true);
+        settings.setSupportMultipleWindows(true);
+        settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
+        settings.setDatabaseEnabled(true);
+        settings.setDatabasePath(getDir("databases",0).getAbsolutePath());
+        settings.setDomStorageEnabled(true);
+
+        webview.addJavascriptInterface(callbackProxy, "layoutTestController");
+        webview.addJavascriptInterface(callbackProxy, "eventSender");
+
+        webview.setWebChromeClient(mChromeClient);
+        webview.setWebViewClient(mViewClient);
+    }
+
     private WebView mWebView;
     private WebViewEventSender mEventSender;
     private AsyncHandler mHandler;
@@ -470,6 +574,10 @@
     private StringBuffer mDialogStrings;
     private boolean mKeepWebHistory;
     private Vector mWebHistory;
+    private boolean mDumpDatabaseCallbacks;
+    private StringBuffer mDatabaseCallbackStrings;
+    private StringBuffer mConsoleMessages;
+    private boolean mCanOpenWindows;
 
     static final String TIMEOUT_STR = "**Test timeout";
     
diff --git a/tests/backup/src/com/android/backuptest/BackupTestActivity.java b/tests/backup/src/com/android/backuptest/BackupTestActivity.java
index d87e85c..69da761 100644
--- a/tests/backup/src/com/android/backuptest/BackupTestActivity.java
+++ b/tests/backup/src/com/android/backuptest/BackupTestActivity.java
@@ -17,12 +17,11 @@
 package com.android.backuptest;
 
 import android.app.ListActivity;
+import android.backup.BackupHelperDispatcher;
 import android.backup.BackupDataInput;
 import android.backup.BackupDataOutput;
 import android.backup.BackupManager;
 import android.backup.FileBackupHelper;
-import android.backup.FileRestoreHelper;
-import android.backup.RestoreHelperDispatcher;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
@@ -142,10 +141,10 @@
                             ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE|
                             ParcelFileDescriptor.MODE_TRUNCATE);
                     FileBackupHelper h = new FileBackupHelper(BackupTestActivity.this,
-                            "FileBackupHelper");
+                            new String[] { "a", "empty" });
                     FileOutputStream dataFile = openFileOutput("backup_test", MODE_WORLD_READABLE);
                     BackupDataOutput data = new BackupDataOutput(dataFile.getFD());
-                    h.performBackup(null, data, state, new String[] { "a", "empty" });
+                    h.performBackup(null, data, state);
                     dataFile.close();
                     state.close();
                 } catch (IOException ex) {
@@ -156,13 +155,18 @@
         new Test("Restore Helpers") {
             void run() {
                 try {
-                    RestoreHelperDispatcher dispatch = new RestoreHelperDispatcher();
-                    dispatch.addHelper("FileBackupHelper",
-                            new FileRestoreHelper(BackupTestActivity.this));
+                    BackupHelperDispatcher dispatch = new BackupHelperDispatcher();
+                    dispatch.addHelper("", new FileBackupHelper(BackupTestActivity.this,
+                            new String[] { "a", "empty" }));
                     FileInputStream dataFile = openFileInput("backup_test");
                     BackupDataInput data = new BackupDataInput(dataFile.getFD());
-                    dispatch.dispatch(data);
+                    ParcelFileDescriptor state = ParcelFileDescriptor.open(
+                            new File(getFilesDir(), "restore_state"),
+                            ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE|
+                            ParcelFileDescriptor.MODE_TRUNCATE);
+                    dispatch.performRestore(data, state);
                     dataFile.close();
+                    state.close();
                 } catch (IOException ex) {
                     throw new RuntimeException(ex);
                 }
diff --git a/tests/backup/src/com/android/backuptest/BackupTestAgent.java b/tests/backup/src/com/android/backuptest/BackupTestAgent.java
index e3566ec..c6acc66 100644
--- a/tests/backup/src/com/android/backuptest/BackupTestAgent.java
+++ b/tests/backup/src/com/android/backuptest/BackupTestAgent.java
@@ -16,46 +16,13 @@
 
 package com.android.backuptest;
 
-import android.app.BackupAgent;
-import android.backup.BackupDataInput;
-import android.backup.BackupDataOutput;
+import android.backup.BackupHelperAgent;
 import android.backup.FileBackupHelper;
-import android.backup.FileRestoreHelper;
-import android.backup.RestoreHelperDispatcher;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
 
-import java.io.IOException;
-
-public class BackupTestAgent extends BackupAgent
+public class BackupTestAgent extends BackupHelperAgent
 {
-    static final String TAG = "BackupTestAgent";
-
-    static final String SHARED_PREFS = "shared_prefs";
-    static final String DATA_FILES = "data_files";
-    static final String[] FILES = new String[] {
-                    BackupTestActivity.FILE_NAME
-                };
-
-    @Override
-    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
-             ParcelFileDescriptor newState) {
-        Log.d(TAG, "onBackup");
-
-        (new FileBackupHelper(this, DATA_FILES)).performBackup(oldState, data, newState, FILES);
-    }
-
-    @Override
-    public void onRestore(BackupDataInput data, ParcelFileDescriptor newState)
-            throws IOException {
-        Log.d(TAG, "onRestore");
-
-        RestoreHelperDispatcher dispatch = new RestoreHelperDispatcher();
-
-        // dispatch.addHelper(SHARED_PREFS, new SharedPrefsRestoreHelper(this));
-        dispatch.addHelper(DATA_FILES, new FileRestoreHelper(this));
-
-        dispatch.dispatch(data);
+    public void onCreate() {
+        addHelper("data_files", new FileBackupHelper(this, BackupTestActivity.FILE_NAME));
     }
 }
 
diff --git a/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java
new file mode 100644
index 0000000..dc6860a
--- /dev/null
+++ b/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2009 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 com.android.framework.permission.tests;
+
+import junit.framework.TestCase;
+
+import android.os.Binder;
+import android.os.IHardwareService;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+/**
+ * Verify that Hardware apis cannot be called without required permissions.
+ */
+public class HardwareServicePermissionTest extends TestCase {
+
+    private IHardwareService mHardwareService;
+
+    @Override
+    protected void setUp() throws Exception {
+        mHardwareService = IHardwareService.Stub.asInterface(
+                ServiceManager.getService("hardware"));
+    }
+
+    /**
+     * Test that calling {@link android.os.IHardwareService#vibrate(long)} requires permissions.
+     * <p>Tests permission:
+     *   {@link android.Manifest.permission#VIBRATE}
+     * @throws RemoteException
+     */
+    public void testVibrate() throws RemoteException {
+        try {
+            mHardwareService.vibrate(2000);
+            fail("vibrate did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Test that calling {@link android.os.IHardwareService#vibratePattern(long[],
+     * int, android.os.IBinder)} requires permissions.
+     * <p>Tests permission:
+     *   {@link android.Manifest.permission#VIBRATE}
+     * @throws RemoteException
+     */
+    public void testVibratePattern() throws RemoteException {
+        try {
+            mHardwareService.vibratePattern(new long[] {0}, 0, new Binder());
+            fail("vibratePattern did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Test that calling {@link android.os.IHardwareService#cancelVibrate()} requires permissions.
+     * <p>Tests permission:
+     *   {@link android.Manifest.permission#VIBRATE}
+     * @throws RemoteException
+     */
+    public void testCancelVibrate() throws RemoteException {
+        try {
+            mHardwareService.cancelVibrate();
+            fail("cancelVibrate did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Test that calling {@link android.os.IHardwareService#setFlashlightEnabled(boolean)}
+     * requires permissions.
+     * <p>Tests permissions:
+     *   {@link android.Manifest.permission#HARDWARE_TEST}
+     *   {@link android.Manifest.permission#FLASHLIGHT}
+     * @throws RemoteException
+     */
+    public void testSetFlashlightEnabled() throws RemoteException {
+        try {
+            mHardwareService.setFlashlightEnabled(true);
+            fail("setFlashlightEnabled did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Test that calling {@link android.os.IHardwareService#enableCameraFlash(int)} requires
+     * permissions.
+     * <p>Tests permission:
+     *   {@link android.Manifest.permission#HARDWARE_TEST}
+     *   {@link android.Manifest.permission#CAMERA}
+     * @throws RemoteException
+     */
+    public void testEnableCameraFlash() throws RemoteException {
+        try {
+            mHardwareService.enableCameraFlash(100);
+            fail("enableCameraFlash did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Test that calling {@link android.os.IHardwareService#setBacklights(int)} requires
+     * permissions.
+     * <p>Tests permission:
+     *   {@link android.Manifest.permission#HARDWARE_TEST}
+     * @throws RemoteException
+     */
+    public void testSetBacklights() throws RemoteException {
+        try {
+            mHardwareService.setBacklights(0);
+            fail("setBacklights did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+}
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 9e712b8..a671bd7 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -37,6 +37,7 @@
           mForce(false), mGrayscaleTolerance(0), mMakePackageDirs(false),
           mUpdate(false), mExtending(false),
           mRequireLocalization(false), mPseudolocalize(false),
+          mValues(false),
           mCompressionMethod(0), mOutputAPKFile(NULL),
           mAssetSourceDir(NULL),
           mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
@@ -75,6 +76,8 @@
     void setRequireLocalization(bool val) { mRequireLocalization = val; }
     bool getPseudolocalize(void) const { return mPseudolocalize; }
     void setPseudolocalize(bool val) { mPseudolocalize = val; }
+    bool getValues(void) const { return mValues; }
+    void setValues(bool val) { mValues = val; }
     int getCompressionMethod(void) const { return mCompressionMethod; }
     void setCompressionMethod(int val) { mCompressionMethod = val; }
     const char* getOutputAPKFile() const { return mOutputAPKFile; }
@@ -154,6 +157,7 @@
     bool        mExtending;
     bool        mRequireLocalization;
     bool        mPseudolocalize;
+    bool        mValues;
     int         mCompressionMethod;
     const char* mOutputAPKFile;
     const char* mAssetSourceDir;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 0e889f5..dcda379 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -198,7 +198,7 @@
             printf("\nNo resource table found.\n");
         } else {
             printf("\nResource table:\n");
-            res.print();
+            res.print(false);
         }
 
         Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
@@ -382,7 +382,7 @@
     }
 
     if (strcmp("resources", option) == 0) {
-        res.print();
+        res.print(bundle->getValues());
 
     } else if (strcmp("xmltree", option) == 0) {
         if (bundle->getFileSpecCount() < 3) {
@@ -734,11 +734,12 @@
                            activityIcon.string());
                 }
             }
+            
             printf("locales:");
             Vector<String8> locales;
             res.getLocales(&locales);
-            const size_t N = locales.size();
-            for (size_t i=0; i<N; i++) {
+            const size_t NL = locales.size();
+            for (size_t i=0; i<NL; i++) {
                 const char* localeStr =  locales[i].string();
                 if (localeStr == NULL || strlen(localeStr) == 0) {
                     localeStr = "--_--";
@@ -746,6 +747,24 @@
                 printf(" '%s'", localeStr);
             }
             printf("\n");
+            
+            Vector<ResTable_config> configs;
+            res.getConfigurations(&configs);
+            SortedVector<int> densities;
+            const size_t NC = configs.size();
+            for (size_t i=0; i<NC; i++) {
+                int dens = configs[i].density;
+                if (dens == 0) dens = 160;
+                densities.add(dens);
+            }
+            
+            printf("densities:");
+            const size_t ND = densities.size();
+            for (size_t i=0; i<ND; i++) {
+                printf(" '%d'", densities[i]);
+            }
+            printf("\n");
+            
             AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
             if (dir != NULL) {
                 if (dir->getFileCount() > 0) {
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index a33b4d7..882714c 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -47,7 +47,7 @@
         " %s l[ist] [-v] [-a] file.{zip,jar,apk}\n"
         "   List contents of Zip-compatible archive.\n\n", gProgName);
     fprintf(stderr,
-        " %s d[ump] WHAT file.{apk} [asset [asset ...]]\n"
+        " %s d[ump] [--values] WHAT file.{apk} [asset [asset ...]]\n"
         "   badging          Print the label and icon for the app declared in APK.\n"
         "   permissions      Print the permissions from the APK.\n"
         "   resources        Print the resource table from the APK.\n"
@@ -125,6 +125,8 @@
         "       inserts android:targetSdkVersion in to manifest.\n"
         "   --max-sdk-version\n"
         "       inserts android:maxSdkVersion in to manifest.\n"
+        "   --values\n"
+        "       when used with \"dump resources\" also includes resource values.\n"
         "   --version-code\n"
         "       inserts android:versionCode in to manifest.\n"
         "   --version-name\n"
@@ -398,6 +400,8 @@
                         goto bail;
                     }
                     bundle.setVersionName(argv[0]);
+                } else if (strcmp(cp, "-values") == 0) {
+                    bundle.setValues(true);
                 } else {
                     fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp);
                     wantUsage = true;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
index d0896b5..69f3d9c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
@@ -29,6 +29,7 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
 import android.content.res.Configuration;
@@ -960,6 +961,12 @@
     }
 
     @Override
+    public ApplicationInfo getApplicationInfo() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+    
+    @Override
     public String getPackageResourcePath() {
         // TODO Auto-generated method stub
         return null;