Merge change 6367 into donut

* changes:
  Add virtual destructor.
diff --git a/api/current.xml b/api/current.xml
index b1e042b..9bce1f3 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -27810,6 +27810,17 @@
 <parameter name="modeFlags" type="int">
 </parameter>
 </method>
+<method name="isRestricted"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="obtainStyledAttributes"
  return="android.content.res.TypedArray"
  abstract="false"
@@ -28323,6 +28334,17 @@
  visibility="public"
 >
 </field>
+<field name="CONTEXT_RESTRICTED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="INPUT_METHOD_SERVICE"
  type="java.lang.String"
  transient="false"
@@ -139718,6 +139740,21 @@
 <parameter name="units" type="int">
 </parameter>
 </method>
+<method name="computeCurrentVelocity"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="units" type="int">
+</parameter>
+<parameter name="maxVelocity" type="float">
+</parameter>
+</method>
 <method name="getXVelocity"
  return="float"
  abstract="false"
@@ -144121,6 +144158,17 @@
  visibility="public"
 >
 </method>
+<method name="getMaximumFlingVelocity"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+</method>
 <method name="getMinimumFlingVelocity"
  return="int"
  abstract="false"
@@ -144187,6 +144235,17 @@
  visibility="public"
 >
 </method>
+<method name="getScaledMaximumFlingVelocity"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getScaledMinimumFlingVelocity"
  return="int"
  abstract="false"
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 00b0593..38ea686 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -88,8 +88,10 @@
 import android.telephony.TelephonyManager;
 import android.text.ClipboardManager;
 import android.util.AndroidRuntimeException;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
+import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.WindowManagerImpl;
 import android.view.accessibility.AccessibilityManager;
@@ -149,6 +151,7 @@
  */
 class ApplicationContext extends Context {
     private final static String TAG = "ApplicationContext";
+    private final static boolean DEBUG = false;
     private final static boolean DEBUG_ICONS = false;
 
     private static final Object sSync = new Object();
@@ -184,6 +187,7 @@
     private StatusBarManager mStatusBarManager = null;
     private TelephonyManager mTelephonyManager = null;
     private ClipboardManager mClipboardManager = null;
+    private boolean mRestricted;
 
     private final Object mSync = new Object();
 
@@ -1237,7 +1241,7 @@
     @Override
     public int checkUriPermission(Uri uri, String readPermission,
             String writePermission, int pid, int uid, int modeFlags) {
-        if (false) {
+        if (DEBUG) {
             Log.i("foo", "checkUriPermission: uri=" + uri + "readPermission="
                     + readPermission + " writePermission=" + writePermission
                     + " pid=" + pid + " uid=" + uid + " mode" + modeFlags);
@@ -1336,8 +1340,22 @@
             mMainThread.getPackageInfo(packageName, flags);
         if (pi != null) {
             ApplicationContext c = new ApplicationContext();
+            c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
             c.init(pi, null, mMainThread);
             if (c.mResources != null) {
+                Resources newRes = c.mResources;
+                if (mResources.getCompatibilityInfo().applicationScale !=
+                    newRes.getCompatibilityInfo().applicationScale) {
+                    DisplayMetrics dm = mMainThread.getDisplayMetricsLocked(false);
+                    c.mResources = new Resources(newRes.getAssets(), dm,
+                            newRes.getConfiguration(),
+                            mResources.getCompatibilityInfo().copy());
+                    if (DEBUG) {
+                        Log.d(TAG, "loaded context has different scaling. Using container's" +
+                                " compatiblity info:" + mResources.getDisplayMetrics());
+                    }
+
+                }
                 return c;
             }
         }
@@ -1347,6 +1365,11 @@
             "Application package " + packageName + " not found");
     }
 
+    @Override
+    public boolean isRestricted() {
+        return mRestricted;
+    }
+
     private File getDataDirFile() {
         if (mPackageInfo != null) {
             return mPackageInfo.getDataDirFile();
@@ -1452,7 +1475,7 @@
         if ((mode&MODE_WORLD_WRITEABLE) != 0) {
             perms |= FileUtils.S_IWOTH;
         }
-        if (false) {
+        if (DEBUG) {
             Log.i(TAG, "File " + name + ": mode=0x" + Integer.toHexString(mode)
                   + ", perms=0x" + Integer.toHexString(perms));
         }
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 0785029..fdb619a 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -1573,6 +1573,15 @@
         }
         
         /**
+         * We override this method to avoid an extra onItemClick being called on the
+         * drop-down's OnItemClickListener by {@link AutoCompleteTextView#onKeyUp(int, KeyEvent)}
+         * when an item is clicked with the trackball.
+         */
+        @Override
+        public void performCompletion() {
+        }
+        
+        /**
          * We override this method so that we can allow a threshold of zero, which ACTV does not.
          */
         @Override
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 307c4c8..62d9267 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -269,7 +269,7 @@
         try {
             if (mInfo != null) {
                 Context theirContext = mContext.createPackageContext(
-                        mInfo.provider.getPackageName(), 0 /* no flags */);
+                        mInfo.provider.getPackageName(), Context.CONTEXT_RESTRICTED);
                 LayoutInflater inflater = (LayoutInflater)
                         theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                 inflater = inflater.cloneInContext(theirContext);
diff --git a/core/java/android/backup/BackupManager.java b/core/java/android/backup/BackupManager.java
index 5b4ac0d..34a1a0c 100644
--- a/core/java/android/backup/BackupManager.java
+++ b/core/java/android/backup/BackupManager.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.util.Log;
 
 /**
  * BackupManager is the interface to the system's backup service.
@@ -39,14 +40,17 @@
  * @hide pending API solidification
  */
 public class BackupManager {
-    private Context mContext;
-    private IBackupManager mService;
+    private static final String TAG = "BackupManager";
 
-    /**
-     * Defined backup transports understood by {@link IBackupManager.selectBackupTransport}.
-     */
-    public static final int TRANSPORT_LOCAL = 1;
-    public static final int TRANSPORT_GOOGLE = 2;
+    private Context mContext;
+    private static IBackupManager sService;
+
+    private static void checkServiceBinder() {
+        if (sService == null) {
+            sService = IBackupManager.Stub.asInterface(
+                    ServiceManager.getService(Context.BACKUP_SERVICE));
+        }
+    }
 
     /**
      * Constructs a BackupManager object through which the application can
@@ -58,8 +62,6 @@
      */
     public BackupManager(Context context) {
         mContext = context;
-        mService = IBackupManager.Stub.asInterface(
-                ServiceManager.getService(Context.BACKUP_SERVICE));
     }
 
     /**
@@ -68,10 +70,31 @@
      * {@link android.app.BackupAgent} subclass will be scheduled when you call this method.
      */
     public void dataChanged() {
-        if (mService != null) {
+        checkServiceBinder();
+        if (sService != null) {
             try {
-                mService.dataChanged(mContext.getPackageName());
+                sService.dataChanged(mContext.getPackageName());
             } catch (RemoteException e) {
+                Log.d(TAG, "dataChanged() couldn't connect");
+            }
+        }
+    }
+
+    /**
+     * Convenience method for callers who need to indicate that some other package
+     * needs a backup pass.  This can be relevant in the case of groups of packages
+     * that share a uid, for example.
+     *
+     * This method requires that the application hold the "android.permission.BACKUP"
+     * permission if the package named in the argument is not the caller's own.
+     */
+    public static void dataChanged(String packageName) {
+        checkServiceBinder();
+        if (sService != null) {
+            try {
+                sService.dataChanged(packageName);
+            } catch (RemoteException e) {
+                Log.d(TAG, "dataChanged(pkg) couldn't connect");
             }
         }
     }
@@ -85,10 +108,12 @@
      */
     public IRestoreSession beginRestoreSession(String transport) {
         IRestoreSession binder = null;
-        if (mService != null) {
+        checkServiceBinder();
+        if (sService != null) {
             try {
-                binder = mService.beginRestoreSession(transport);
+                binder = sService.beginRestoreSession(transport);
             } catch (RemoteException e) {
+                Log.d(TAG, "beginRestoreSession() couldn't connect");
             }
         }
         return binder;
diff --git a/core/java/android/backup/IBackupManager.aidl b/core/java/android/backup/IBackupManager.aidl
index d4933ac..9d181be 100644
--- a/core/java/android/backup/IBackupManager.aidl
+++ b/core/java/android/backup/IBackupManager.aidl
@@ -73,6 +73,13 @@
     void setBackupEnabled(boolean isEnabled);
 
     /**
+     * Indicate that any necessary one-time provisioning has occurred.
+     *
+     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     */
+    void setBackupProvisioned(boolean isProvisioned);
+
+    /**
      * Report whether the backup mechanism is currently enabled.
      *
      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index b0396f6..9e37ae4 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1654,6 +1654,13 @@
      * with extreme care!
      */
     public static final int CONTEXT_IGNORE_SECURITY = 0x00000002;
+    
+    /**
+     * Flag for use with {@link #createPackageContext}: a restricted context may
+     * disable specific features. For instance, a View associated with a restricted
+     * context would ignore particular XML attributes.
+     */
+    public static final int CONTEXT_RESTRICTED = 0x00000004;
 
     /**
      * Return a new Context object for the given application name.  This
@@ -1682,4 +1689,15 @@
      */
     public abstract Context createPackageContext(String packageName,
             int flags) throws PackageManager.NameNotFoundException;
+
+    /**
+     * Indicates whether this Context is restricted.
+     * 
+     * @return True if this Context is restricted, false otherwise.
+     * 
+     * @see #CONTEXT_RESTRICTED
+     */
+    public boolean isRestricted() {
+        return false;
+    }
 }
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 7513b3b..45a082a 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -430,4 +430,9 @@
         throws PackageManager.NameNotFoundException {
         return mBase.createPackageContext(packageName, flags);
     }
+
+    @Override
+    public boolean isRestricted() {
+        return mBase.isRestricted();
+    }
 }
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index 9c25e73..f781e0d0 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -24,6 +24,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import android.backup.IBackupManager;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteException;
@@ -35,6 +36,7 @@
 import android.os.Parcel;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.Xml;
@@ -351,8 +353,18 @@
                 }
             }
         }
+        // Inform the backup manager about a data change
+        IBackupManager ibm = IBackupManager.Stub.asInterface(
+                ServiceManager.getService(Context.BACKUP_SERVICE));
+        if (ibm != null) {
+            try {
+                ibm.dataChanged("com.android.providers.settings");
+            } catch (RemoteException e) {
+                // Try again later
+            }
+        }
     }
-    
+
     public boolean getSyncProviderAutomatically(String account, String providerName) {
         synchronized (mAuthorities) {
             if (account != null) {
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 4e6fe07..dfe304d 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -159,14 +159,32 @@
         }
     }
 
-    private CompatibilityInfo() {
-        appFlags = ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
-                | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS
-                | ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
-        applicationScale = applicationInvertedScale = 1.0f;
-        mCompatibilityFlags = EXPANDABLE | CONFIGURED_EXPANDABLE;
+    private CompatibilityInfo(int appFlags, int compFlags, float scale, float invertedScale) {
+        this.appFlags = appFlags;
+        mCompatibilityFlags = compFlags;
+        applicationScale = scale;
+        applicationInvertedScale = invertedScale;
     }
 
+    private CompatibilityInfo() {
+        this(ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
+                | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS
+                | ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS,
+                EXPANDABLE | CONFIGURED_EXPANDABLE,
+                1.0f,
+                1.0f);
+    }
+
+    /**
+     * Returns the copy of this instance.
+     */
+    public CompatibilityInfo copy() {
+        CompatibilityInfo info = new CompatibilityInfo(appFlags, mCompatibilityFlags,
+                applicationScale, applicationInvertedScale);
+        info.setVisibleRect(mXOffset, mWidth, mHeight);
+        return info;
+    }
+ 
     /**
      * Sets the application's visible rect in compatibility mode.
      * @param xOffset the application's x offset that is added to center the content.
@@ -470,4 +488,4 @@
             return mVisibleInsets;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index d7512bb..49ad656 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -129,7 +129,7 @@
      */
     public Resources(AssetManager assets, DisplayMetrics metrics,
             Configuration config) {
-        this(assets, metrics, config, null);
+        this(assets, metrics, config, (ApplicationInfo) null);
     }
 
     /**
@@ -166,6 +166,26 @@
     }
 
     /**
+     * Creates a new resources that uses the given compatibility info. Used to create
+     * a context for widgets using the container's compatibility info.
+     * {@see ApplicationContext#createPackageCotnext}.
+     * @hide
+     */
+    public Resources(AssetManager assets, DisplayMetrics metrics,
+            Configuration config, CompatibilityInfo info) {
+        mAssets = assets;
+        mMetrics.setToDefaults();
+        mCompatibilityInfo = info;
+        updateConfiguration(config, metrics);
+        assets.ensureStringBlocks();
+        if (mCompatibilityInfo.isScalingRequired()) {
+            mPreloadedDrawables = emptySparseArray();
+        } else {
+            mPreloadedDrawables = sPreloadedDrawables;
+        }
+    }
+
+    /**
      * Return a global shared Resources object that provides access to only
      * system resources (no application resources), and is not configured for 
      * the current screen (can not use dimension units, does not change based 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7017333..0d27e1e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2269,13 +2269,20 @@
         public static final String USE_LOCATION_FOR_SERVICES = "use_location";
 
         /**
-         * Controls whether data backup is enabled.
+         * Controls whether settings backup is enabled.
          * Type: int ( 0 = disabled, 1 = enabled )
          * @hide
          */
         public static final String BACKUP_ENABLED = "backup_enabled";
 
         /**
+         * Indicates whether settings backup has been fully provisioned.
+         * Type: int ( 0 = unprovisioned, 1 = fully provisioned )
+         * @hide
+         */
+        public static final String BACKUP_PROVISIONED = "backup_provisioned";
+
+        /**
          * Component of the transport to use for backup/restore.
          * @hide
          */
@@ -2664,6 +2671,12 @@
         public static final String GMAIL_DISCARD_ERROR_UPHILL_OP = "gmail_discard_error_uphill_op";
 
         /**
+         * Controls how many attempts Gmail will try to upload an uphill operations before it
+         * abandons the operation. Defaults to 20.
+         */
+        public static final String GMAIL_NUM_RETRY_UPHILL_OP = "gmail_discard_error_uphill_op";
+
+        /**
          * the transcoder URL for mobile devices.
          */
         public static final String TRANSCODER_URL = "mobile_transcoder_url";
diff --git a/core/java/android/speech/tts/ITts.aidl b/core/java/android/speech/tts/ITts.aidl
index 5612ecd..c9a6180 100755
--- a/core/java/android/speech/tts/ITts.aidl
+++ b/core/java/android/speech/tts/ITts.aidl
@@ -27,15 +27,15 @@
  * {@hide}

  */

 interface ITts {

-    void setSpeechRate(in int speechRate);

+    int setSpeechRate(in int speechRate);

 

-    void setPitch(in int pitch);

+    int setPitch(in int pitch);

 

-    void speak(in String text, in int queueMode, in String[] params);

+    int speak(in String text, in int queueMode, in String[] params);

 

     boolean isSpeaking();

 

-    void stop();

+    int stop();

 

     void addSpeech(in String text, in String packageName, in int resId);

 

@@ -45,11 +45,11 @@
 

     int isLanguageAvailable(in String language, in String country, in String variant);

 

-    void setLanguage(in String language, in String country, in String variant);

+    int setLanguage(in String language, in String country, in String variant);

 

     boolean synthesizeToFile(in String text, in String[] params, in String outputDirectory);

 

-    void playEarcon(in String earcon, in int queueMode, in String[] params);

+    int playEarcon(in String earcon, in int queueMode, in String[] params);

 

     void addEarcon(in String earcon, in String packageName, in int resId);

 

@@ -59,5 +59,5 @@
 

     void unregisterCallback(ITtsCallback cb);

 

-    void playSilence(in long duration, in int queueMode, in String[] params);

+    int playSilence(in long duration, in int queueMode, in String[] params);

 }

diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index f714dd9..61e182a 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -207,7 +207,7 @@
             }
         };
 
-        Intent intent = new Intent("android.intent.action.USE_TTS");
+        Intent intent = new Intent("android.intent.action.START_TTS_SERVICE");
         intent.addCategory("android.intent.category.TTS");
         mContext.bindService(intent, mServiceConnection,
                 Context.BIND_AUTO_CREATE);
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 23f3e3c..1e558be 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -198,6 +198,7 @@
     private int mTouchSlopSquare;
     private int mDoubleTapSlopSquare;
     private int mMinimumFlingVelocity;
+    private int mMaximumFlingVelocity;
 
     private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout();
     private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
@@ -361,11 +362,13 @@
             doubleTapSlop = ViewConfiguration.getDoubleTapSlop();
             //noinspection deprecation
             mMinimumFlingVelocity = ViewConfiguration.getMinimumFlingVelocity();
+            mMaximumFlingVelocity = ViewConfiguration.getMaximumFlingVelocity();
         } else {
             final ViewConfiguration configuration = ViewConfiguration.get(context);
             touchSlop = configuration.getScaledTouchSlop();
             doubleTapSlop = configuration.getScaledDoubleTapSlop();
             mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity();
+            mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity();
         }
         mTouchSlopSquare = touchSlop * touchSlop;
         mDoubleTapSlopSquare = doubleTapSlop * doubleTapSlop;
@@ -505,7 +508,7 @@
 
                 // A fling must travel the minimum tap distance
                 final VelocityTracker velocityTracker = mVelocityTracker;
-                velocityTracker.computeCurrentVelocity(1000);
+                velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
                 final float velocityY = velocityTracker.getYVelocity();
                 final float velocityX = velocityTracker.getXVelocity();
 
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index c708f54..5d89c46 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -165,7 +165,17 @@
             pastTime[i] = 0;
         }
     }
-    
+
+    /**
+     * Equivalent to invoking {@link #computeCurrentVelocity(int, float)} with a maximum
+     * velocity of Float.MAX_VALUE.
+     * 
+     * @see #computeCurrentVelocity(int, float) 
+     */
+    public void computeCurrentVelocity(int units) {
+        computeCurrentVelocity(units, Float.MAX_VALUE);
+    }
+
     /**
      * Compute the current velocity based on the points that have been
      * collected.  Only call this when you actually want to retrieve velocity
@@ -175,8 +185,11 @@
      * 
      * @param units The units you would like the velocity in.  A value of 1
      * provides pixels per millisecond, 1000 provides pixels per second, etc.
+     * @param maxVelocity The maximum velocity that can be computed by this method.
+     * This value must be declared in the same unit as the units parameter. This value
+     * must be positive.
      */
-    public void computeCurrentVelocity(int units) {
+    public void computeCurrentVelocity(int units, float maxVelocity) {
         final float[] pastX = mPastX;
         final float[] pastY = mPastY;
         final long[] pastTime = mPastTime;
@@ -210,8 +223,8 @@
             if (accumY == 0) accumY = vel;
             else accumY = (accumY + vel) * .5f;
         }
-        mXVelocity = accumX;
-        mYVelocity = accumY;
+        mXVelocity = accumX < 0.0f ? Math.max(accumX, -maxVelocity) : Math.min(accumX, maxVelocity);
+        mYVelocity = accumY < 0.0f ? Math.max(accumY, -maxVelocity) : Math.min(accumY, maxVelocity);
         
         if (localLOGV) Log.v(TAG, "Y velocity=" + mYVelocity +" X velocity="
                 + mXVelocity + " N=" + N);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b3180ca..ff8868b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1996,6 +1996,11 @@
                     mMinHeight = a.getDimensionPixelSize(attr, 0);
                     break;
                 case R.styleable.View_onClick:
+                    if (context.isRestricted()) {
+                        throw new IllegalStateException("The android:onClick attribute cannot " 
+                                + "be used within a restricted context");
+                    }
+
                     final String handlerName = a.getString(attr);
                     if (handlerName != null) {
                         setOnClickListener(new OnClickListener() {
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 8e1524b..0e36ec2 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -106,6 +106,11 @@
      * Minimum velocity to initiate a fling, as measured in pixels per second
      */
     private static final int MINIMUM_FLING_VELOCITY = 50;
+    
+    /**
+     * Maximum velocity to initiate a fling, as measured in pixels per second
+     */
+    private static final int MAXIMUM_FLING_VELOCITY = 4000;
 
     /**
      * The maximum size of View's drawing cache, expressed in bytes. This size
@@ -122,6 +127,7 @@
     private final int mEdgeSlop;
     private final int mFadingEdgeLength;
     private final int mMinimumFlingVelocity;
+    private final int mMaximumFlingVelocity;
     private final int mScrollbarSize;
     private final int mTouchSlop;
     private final int mDoubleTapSlop;
@@ -139,6 +145,7 @@
         mEdgeSlop = EDGE_SLOP;
         mFadingEdgeLength = FADING_EDGE_LENGTH;
         mMinimumFlingVelocity = MINIMUM_FLING_VELOCITY;
+        mMaximumFlingVelocity = MAXIMUM_FLING_VELOCITY;
         mScrollbarSize = SCROLL_BAR_SIZE;
         mTouchSlop = TOUCH_SLOP;
         mDoubleTapSlop = DOUBLE_TAP_SLOP;
@@ -164,6 +171,7 @@
         mEdgeSlop = (int) (density * EDGE_SLOP + 0.5f);
         mFadingEdgeLength = (int) (density * FADING_EDGE_LENGTH + 0.5f);
         mMinimumFlingVelocity = (int) (density * MINIMUM_FLING_VELOCITY + 0.5f);
+        mMaximumFlingVelocity = (int) (density * MAXIMUM_FLING_VELOCITY + 0.5f);
         mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
         mTouchSlop = (int) (density * TOUCH_SLOP + 0.5f);
         mDoubleTapSlop = (int) (density * DOUBLE_TAP_SLOP + 0.5f);
@@ -367,6 +375,23 @@
     }
 
     /**
+     * @return Maximum velocity to initiate a fling, as measured in pixels per second.
+     *
+     * @deprecated Use {@link #getScaledMaximumFlingVelocity()} instead.
+     */
+    @Deprecated
+    public static int getMaximumFlingVelocity() {
+        return MAXIMUM_FLING_VELOCITY;
+    }
+
+    /**
+     * @return Maximum velocity to initiate a fling, as measured in pixels per second.
+     */
+    public int getScaledMaximumFlingVelocity() {
+        return mMaximumFlingVelocity;
+    }
+    
+    /**
      * The maximum drawing cache size expressed in bytes.
      *
      * @return the maximum size of View's drawing cache expressed in bytes
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 65457c5..6f6e2247 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -546,13 +546,16 @@
         if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
         if (mCurScrollY != 0 || mTranslator != null) {
             mTempRect.set(dirty);
+            dirty = mTempRect;
             if (mCurScrollY != 0) {
-               mTempRect.offset(0, -mCurScrollY);
+               dirty.offset(0, -mCurScrollY);
             }
             if (mTranslator != null) {
-                mTranslator.translateRectInAppWindowToScreen(mTempRect);
+                mTranslator.translateRectInAppWindowToScreen(dirty);
             }
-            dirty = mTempRect;
+            if (mAttachInfo.mScalingRequired) {
+                dirty.inset(-1, -1);
+            }
         }
         mDirty.union(dirty);
         if (!mWillDrawSoon) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 429f0f9..fcf946f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -237,6 +237,7 @@
      * Helper class to get velocity for fling
      */
     VelocityTracker mVelocityTracker;
+    private int mMaximumFling;
 
     /**
      * Touch mode
@@ -676,7 +677,8 @@
         setClickable(true);
         setLongClickable(true);
 
-        final int slop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+        final ViewConfiguration configuration = ViewConfiguration.get(getContext());
+        final int slop = configuration.getScaledTouchSlop();
         mTouchSlopSquare = slop * slop;
         mMinLockSnapReverseDistance = slop;
         final float density = getContext().getResources().getDisplayMetrics().density;
@@ -692,6 +694,7 @@
         DEFAULT_MIN_ZOOM_SCALE = 0.25f * density;
         mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
         mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
+        mMaximumFling = configuration.getScaledMaximumFlingVelocity();
     }
 
     /* package */void updateDefaultZoomDensity(int zoomDensity) {
@@ -4157,7 +4160,7 @@
         int maxX = Math.max(computeHorizontalScrollRange() - getViewWidth(), 0);
         int maxY = Math.max(computeVerticalScrollRange() - getViewHeight(), 0);
 
-        mVelocityTracker.computeCurrentVelocity(1000);
+        mVelocityTracker.computeCurrentVelocity(1000, mMaximumFling);
         int vx = (int) mVelocityTracker.getXVelocity();
         int vy = (int) mVelocityTracker.getYVelocity();
 
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 23a38db..f9ca8cb 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -438,6 +438,8 @@
     private InputConnectionWrapper mPublicInputConnection;
 
     private Runnable mClearScrollingCache;
+    private int mMinimumVelocity;
+    private int mMaximumVelocity;
 
     /**
      * Interface definition for a callback to be invoked when the list or grid
@@ -549,7 +551,10 @@
         setAlwaysDrawnWithCacheEnabled(false);
         setScrollingCacheEnabled(true);
 
-        mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+        final ViewConfiguration configuration = ViewConfiguration.get(mContext);
+        mTouchSlop = configuration.getScaledTouchSlop();
+        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
+        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
         mDensityScale = getContext().getResources().getDisplayMetrics().density;
     }
 
@@ -2058,12 +2063,9 @@
                 break;
             case TOUCH_MODE_SCROLL:
                 final VelocityTracker velocityTracker = mVelocityTracker;
-                velocityTracker.computeCurrentVelocity(1000);
-                int initialVelocity = (int)velocityTracker.getYVelocity();
-
-                if ((Math.abs(initialVelocity) >
-                        ViewConfiguration.get(mContext).getScaledMinimumFlingVelocity()) &&
-                        (getChildCount() > 0)) {
+                velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+                final int initialVelocity = (int) velocityTracker.getYVelocity();
+                if (Math.abs(initialVelocity) > mMinimumVelocity && (getChildCount() > 0)) {
                     if (mFlingRunnable == null) {
                         mFlingRunnable = new FlingRunnable();
                     }
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 02fc7c6..f86b37c 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -114,6 +114,8 @@
     private boolean mSmoothScrollingEnabled = true;
 
     private int mTouchSlop;
+    private int mMinimumVelocity;
+    private int mMaximumVelocity;
 
     public HorizontalScrollView(Context context) {
         this(context, null);
@@ -179,7 +181,10 @@
         setFocusable(true);
         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
         setWillNotDraw(false);
-        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+        final ViewConfiguration configuration = ViewConfiguration.get(mContext);
+        mTouchSlop = configuration.getScaledTouchSlop();
+        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
+        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
     }
 
     @Override
@@ -477,12 +482,10 @@
                 break;
             case MotionEvent.ACTION_UP:
                 final VelocityTracker velocityTracker = mVelocityTracker;
-                velocityTracker.computeCurrentVelocity(1000);
+                velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                 int initialVelocity = (int) velocityTracker.getXVelocity();
 
-                if ((Math.abs(initialVelocity) >
-                        ViewConfiguration.get(mContext).getScaledMinimumFlingVelocity()) &&
-                        getChildCount() > 0) {
+                if ((Math.abs(initialVelocity) > mMinimumVelocity) && getChildCount() > 0) {
                     fling(-initialVelocity);
                 }
 
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 1b5c5bc..2dac652 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -856,7 +856,7 @@
 
         if (packageName != null) {
             try {
-                c = context.createPackageContext(packageName, 0);
+                c = context.createPackageContext(packageName, Context.CONTEXT_RESTRICTED);
             } catch (NameNotFoundException e) {
                 Log.e(LOG_TAG, "Package name " + packageName + " not found");
                 c = context;
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index c9b3751..90e1242 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -115,6 +115,8 @@
     private boolean mSmoothScrollingEnabled = true;
 
     private int mTouchSlop;
+    private int mMinimumVelocity;
+    private int mMaximumVelocity;
 
     public ScrollView(Context context) {
         this(context, null);
@@ -180,7 +182,10 @@
         setFocusable(true);
         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
         setWillNotDraw(false);
-        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+        final ViewConfiguration configuration = ViewConfiguration.get(mContext);
+        mTouchSlop = configuration.getScaledTouchSlop();
+        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
+        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
     }
 
     @Override
@@ -478,12 +483,10 @@
                 break;
             case MotionEvent.ACTION_UP:
                 final VelocityTracker velocityTracker = mVelocityTracker;
-                velocityTracker.computeCurrentVelocity(1000);
+                velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                 int initialVelocity = (int) velocityTracker.getYVelocity();
 
-                if ((Math.abs(initialVelocity) >
-                        ViewConfiguration.get(mContext).getScaledMinimumFlingVelocity()) &&
-                        getChildCount() > 0) {
+                if ((Math.abs(initialVelocity) > mMinimumVelocity) && getChildCount() > 0) {
                     fling(-initialVelocity);
                 }
 
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 42ada54..e7d4694 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -539,16 +539,17 @@
 
 
 // ----------------------------------------------------------------------------
-static void android_media_AudioTrack_set_playback_rate(JNIEnv *env,  jobject thiz,
+static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env,  jobject thiz,
         jint sampleRateInHz) {
     AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
                 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
 
     if (lpTrack) {
-        lpTrack->setSampleRate(sampleRateInHz);   
+        return android_media_translateErrorCode(lpTrack->setSampleRate(sampleRateInHz));
     } else {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for setSampleRate()");
+        return AUDIOTRACK_ERROR;
     }
 }
 
@@ -788,7 +789,7 @@
     {"native_get_native_frame_count",
                              "()I",      (void *)android_media_AudioTrack_get_native_frame_count},
     {"native_set_playback_rate",
-                             "(I)V",     (void *)android_media_AudioTrack_set_playback_rate},
+                             "(I)I",     (void *)android_media_AudioTrack_set_playback_rate},
     {"native_get_playback_rate",
                              "()I",      (void *)android_media_AudioTrack_get_playback_rate},
     {"native_set_marker_pos","(I)I",     (void *)android_media_AudioTrack_set_marker_pos},
diff --git a/core/res/res/drawable/rate_star_big_half.png b/core/res/res/drawable/rate_star_big_half.png
index e73ca79..9762292 100644
--- a/core/res/res/drawable/rate_star_big_half.png
+++ b/core/res/res/drawable/rate_star_big_half.png
Binary files differ
diff --git a/core/res/res/drawable/rate_star_big_off.png b/core/res/res/drawable/rate_star_big_off.png
index b4dfa9d..6b5039f 100644
--- a/core/res/res/drawable/rate_star_big_off.png
+++ b/core/res/res/drawable/rate_star_big_off.png
Binary files differ
diff --git a/core/res/res/drawable/rate_star_big_on.png b/core/res/res/drawable/rate_star_big_on.png
index 7442c93..a972db2 100644
--- a/core/res/res/drawable/rate_star_big_on.png
+++ b/core/res/res/drawable/rate_star_big_on.png
Binary files differ
diff --git a/core/res/res/layout/progress_dialog.xml b/core/res/res/layout/progress_dialog.xml
index 2d7afd6..8f66451 100644
--- a/core/res/res/layout/progress_dialog.xml
+++ b/core/res/res/layout/progress_dialog.xml
@@ -33,6 +33,7 @@
         android:paddingBottom="10dip">
 
         <ProgressBar android:id="@android:id/progress"
+            style="@android:style/Widget.ProgressBar"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:max="10000"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ff649d5..9b9ba68 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1193,11 +1193,11 @@
     <string name="lockscreen_pattern_wrong">Sorry, try again</string>
 
     <!-- When the lock screen is showing and the phone plugged in, and the battery
-         is not fully sharted, show the current charge %.  -->
+         is not fully charged, show the current charge %.  -->
     <string name="lockscreen_plugged_in">Charging (<xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g>)</string>
     <!-- When the lock screen is showing, the phone is plugged in and the battery is fully
          charged, say that it is charged. -->
-    <string name="lockscreen_charged">Charged</string>
+    <string name="lockscreen_charged">Charged.</string>
 
     <!-- When the lock screen is showing and the battery is low, warn user to plug
          in the phone soon. -->
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 3694803..13e51ee 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -197,7 +197,6 @@
 
    /* getters, see constructor */
 
-            uint32_t    sampleRate() const;
             int         format() const;
             int         channelCount() const;
             uint32_t    frameCount() const;
@@ -217,7 +216,7 @@
             status_t    stop();
             bool        stopped() const;
 
-    /* get sample rate for this track
+    /* get sample rate for this record track
      */
             uint32_t    getSampleRate();
 
@@ -323,7 +322,6 @@
     sp<ClientRecordThread>  mClientRecordThread;
     Mutex                   mRecordThreadLock;
 
-    uint32_t                mSampleRate;
     uint32_t                mFrameCount;
 
     audio_track_cblk_t*     mCblk;
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index ba0467c..7c86a65 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -201,7 +201,6 @@
     /* getters, see constructor */
 
             int         streamType() const;
-            uint32_t    sampleRate() const;
             int         format() const;
             int         channelCount() const;
             uint32_t    frameCount() const;
@@ -246,7 +245,7 @@
 
     /* set sample rate for this track, mostly used for games' sound effects
      */
-            void        setSampleRate(int sampleRate);
+            status_t    setSampleRate(int sampleRate);
             uint32_t    getSampleRate();
 
     /* Enables looping and sets the start and end points of looping.
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index bda969c..496a739 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -26,7 +26,6 @@
 
 // ----------------------------------------------------------------------------
 
-#define MAX_SAMPLE_RATE     65535
 #define THREAD_PRIORITY_AUDIO_CLIENT (ANDROID_PRIORITY_AUDIO)
 // Maximum cumulated timeout milliseconds before restarting audioflinger thread
 #define MAX_STARTUP_TIMEOUT_MS  3000    // Longer timeout period at startup to cope with A2DP init time
@@ -55,9 +54,9 @@
                     uint16_t    volume[2];
                     uint32_t    volumeLR;
                 };
-                uint16_t    sampleRate;
-                uint16_t    channels;
-                int16_t     flowControlFlag; // underrun (out) or overrrun (in) indication
+                uint32_t    sampleRate;
+                uint8_t     channels;
+                uint8_t     flowControlFlag; // underrun (out) or overrrun (in) indication
                 uint8_t     out;        // out equals 1 for AudioTrack and 0 for AudioRecord
                 uint8_t     forceReady; 
                 uint16_t    bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
diff --git a/include/utils/AssetManager.h b/include/utils/AssetManager.h
index c11429e..d8994e0 100644
--- a/include/utils/AssetManager.h
+++ b/include/utils/AssetManager.h
@@ -251,6 +251,9 @@
         Asset* getResourceTableAsset();
         Asset* setResourceTableAsset(Asset* asset);
 
+        ResTable* getResourceTable();
+        ResTable* setResourceTable(ResTable* res);
+        
         bool isUpToDate();
         
     protected:
@@ -265,6 +268,7 @@
         time_t mModWhen;
 
         Asset* mResourceTableAsset;
+        ResTable* mResourceTable;
 
         static Mutex gLock;
         static DefaultKeyedVector<String8, wp<SharedZip> > gOpen;
@@ -288,8 +292,11 @@
          */
         ZipFileRO* getZip(const String8& path);
 
-        Asset* getZipResourceTable(const String8& path);
-        Asset* setZipResourceTable(const String8& path, Asset* asset);
+        Asset* getZipResourceTableAsset(const String8& path);
+        Asset* setZipResourceTableAsset(const String8& path, Asset* asset);
+
+        ResTable* getZipResourceTable(const String8& path);
+        ResTable* setZipResourceTable(const String8& path, ResTable* res);
 
         // generate path, e.g. "common/en-US-noogle.zip"
         static String8 getPathName(const char* path);
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index eb4151a..93bca4a 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1580,6 +1580,7 @@
                  bool copyData=false);
     status_t add(Asset* asset, void* cookie,
                  bool copyData=false);
+    status_t add(ResTable* src);
 
     status_t getError() const;
 
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 75ca22c..8a19fbd 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -1281,7 +1281,7 @@
     status_t lStatus;
     
     // Resampler implementation limits input sampling rate to 2 x output sampling rate.
-    if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
+    if (sampleRate > mSampleRate*2) {
         LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
         lStatus = BAD_VALUE;
         goto Exit;
@@ -1596,8 +1596,8 @@
                 new(mCblk) audio_track_cblk_t();
                 // clear all buffers
                 mCblk->frameCount = frameCount;
-                mCblk->sampleRate = (uint16_t)sampleRate;
-                mCblk->channels = (uint16_t)channelCount;
+                mCblk->sampleRate = sampleRate;
+                mCblk->channels = (uint8_t)channelCount;
                 if (sharedBuffer == 0) {
                     mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
                     memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
@@ -1620,8 +1620,8 @@
            new(mCblk) audio_track_cblk_t();
            // clear all buffers
            mCblk->frameCount = frameCount;
-           mCblk->sampleRate = (uint16_t)sampleRate;
-           mCblk->channels = (uint16_t)channelCount;
+           mCblk->sampleRate = sampleRate;
+           mCblk->channels = (uint8_t)channelCount;
            mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
            memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
            // Force underrun condition to avoid false underrun callback until first data is
@@ -1682,7 +1682,7 @@
 }
 
 int AudioFlinger::MixerThread::TrackBase::channelCount() const {
-    return mCblk->channels;
+    return (int)mCblk->channels;
 }
 
 void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
@@ -2267,12 +2267,6 @@
         goto Exit;
     }
 
-    if (sampleRate > MAX_SAMPLE_RATE) {
-        LOGE("Sample rate out of range");
-        lStatus = BAD_VALUE;
-        goto Exit;
-    }
-
     if (mAudioRecordThread == 0) {
         LOGE("Audio record thread not started");
         lStatus = NO_INIT;
diff --git a/libs/utils/Asset.cpp b/libs/utils/Asset.cpp
index 91203dd..23cb72d 100644
--- a/libs/utils/Asset.cpp
+++ b/libs/utils/Asset.cpp
@@ -582,11 +582,14 @@
     if ((((size_t)data)&0x3) == 0) {
         // We can return this directly if it is aligned on a word
         // boundary.
+        LOGV("Returning aligned FileAsset %p (%s).", this,
+                getAssetSource());
         return data;
     }
     // If not aligned on a word boundary, then we need to copy it into
     // our own buffer.
-    LOGV("Copying FileAsset %p to buffer size %d to make it aligned.", this, (int)mLength);
+    LOGV("Copying FileAsset %p (%s) to buffer size %d to make it aligned.", this,
+            getAssetSource(), (int)mLength);
     unsigned char* buf = new unsigned char[mLength];
     if (buf == NULL) {
         LOGE("alloc of %ld bytes failed\n", (long) mLength);
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index 4126bfb..5a05e6a 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -395,21 +395,41 @@
     const size_t N = mAssetPaths.size();
     for (size_t i=0; i<N; i++) {
         Asset* ass = NULL;
+        ResTable* sharedRes = NULL;
         bool shared = true;
         const asset_path& ap = mAssetPaths.itemAt(i);
         LOGV("Looking for resource asset in '%s'\n", ap.path.string());
         if (ap.type != kFileTypeDirectory) {
-            ass = const_cast<AssetManager*>(this)->
-                mZipSet.getZipResourceTable(ap.path);
-            if (ass == NULL) {
-                LOGV("loading resource table %s\n", ap.path.string());
+            if (i == 0) {
+                // The first item is typically the framework resources,
+                // which we want to avoid parsing every time.
+                sharedRes = const_cast<AssetManager*>(this)->
+                    mZipSet.getZipResourceTable(ap.path);
+            }
+            if (sharedRes == NULL) {
                 ass = const_cast<AssetManager*>(this)->
-                    openNonAssetInPathLocked("resources.arsc",
-                                             Asset::ACCESS_BUFFER,
-                                             ap);
-                if (ass != NULL && ass != kExcludedAsset) {
+                    mZipSet.getZipResourceTableAsset(ap.path);
+                if (ass == NULL) {
+                    LOGV("loading resource table %s\n", ap.path.string());
                     ass = const_cast<AssetManager*>(this)->
-                        mZipSet.setZipResourceTable(ap.path, ass);
+                        openNonAssetInPathLocked("resources.arsc",
+                                                 Asset::ACCESS_BUFFER,
+                                                 ap);
+                    if (ass != NULL && ass != kExcludedAsset) {
+                        ass = const_cast<AssetManager*>(this)->
+                            mZipSet.setZipResourceTableAsset(ap.path, ass);
+                    }
+                }
+                
+                if (i == 0 && ass != NULL) {
+                    // If this is the first resource table in the asset
+                    // manager, then we are going to cache it so that we
+                    // can quickly copy it out for others.
+                    LOGV("Creating shared resources for %s", ap.path.string());
+                    sharedRes = new ResTable();
+                    sharedRes->add(ass, (void*)(i+1), false);
+                    sharedRes = const_cast<AssetManager*>(this)->
+                        mZipSet.setZipResourceTable(ap.path, sharedRes);
                 }
             }
         } else {
@@ -420,13 +440,19 @@
                                          ap);
             shared = false;
         }
-        if (ass != NULL && ass != kExcludedAsset) {
+        if ((ass != NULL || sharedRes != NULL) && ass != kExcludedAsset) {
             if (rt == NULL) {
                 mResources = rt = new ResTable();
                 updateResourceParamsLocked();
             }
             LOGV("Installing resource asset %p in to table %p\n", ass, mResources);
-            rt->add(ass, (void*)(i+1), !shared);
+            if (sharedRes != NULL) {
+                LOGV("Copying existing resources for %s", ap.path.string());
+                rt->add(sharedRes);
+            } else {
+                LOGV("Parsing resources for %s", ap.path.string());
+                rt->add(ass, (void*)(i+1), !shared);
+            }
 
             if (!shared) {
                 delete ass;
@@ -1510,7 +1536,8 @@
 DefaultKeyedVector<String8, wp<AssetManager::SharedZip> > AssetManager::SharedZip::gOpen;
 
 AssetManager::SharedZip::SharedZip(const String8& path, time_t modWhen)
-    : mPath(path), mZipFile(NULL), mModWhen(modWhen), mResourceTableAsset(NULL)
+    : mPath(path), mZipFile(NULL), mModWhen(modWhen),
+      mResourceTableAsset(NULL), mResourceTable(NULL)
 {
     //LOGI("Creating SharedZip %p %s\n", this, (const char*)mPath);
     mZipFile = new ZipFileRO;
@@ -1563,6 +1590,25 @@
     return mResourceTableAsset;
 }
 
+ResTable* AssetManager::SharedZip::getResourceTable()
+{
+    LOGV("Getting from SharedZip %p resource table %p\n", this, mResourceTable);
+    return mResourceTable;
+}
+
+ResTable* AssetManager::SharedZip::setResourceTable(ResTable* res)
+{
+    {
+        AutoMutex _l(gLock);
+        if (mResourceTable == NULL) {
+            mResourceTable = res;
+            return res;
+        }
+    }
+    delete res;
+    return mResourceTable;
+}
+
 bool AssetManager::SharedZip::isUpToDate()
 {
     time_t modWhen = getFileModDate(mPath.string());
@@ -1572,6 +1618,9 @@
 AssetManager::SharedZip::~SharedZip()
 {
     //LOGI("Destroying SharedZip %p %s\n", this, (const char*)mPath);
+    if (mResourceTable != NULL) {
+        delete mResourceTable;
+    }
     if (mResourceTableAsset != NULL) {
         delete mResourceTableAsset;
     }
@@ -1627,7 +1676,7 @@
     return zip->getZip();
 }
 
-Asset* AssetManager::ZipSet::getZipResourceTable(const String8& path)
+Asset* AssetManager::ZipSet::getZipResourceTableAsset(const String8& path)
 {
     int idx = getIndex(path);
     sp<SharedZip> zip = mZipFile[idx];
@@ -1638,7 +1687,7 @@
     return zip->getResourceTableAsset();
 }
 
-Asset* AssetManager::ZipSet::setZipResourceTable(const String8& path,
+Asset* AssetManager::ZipSet::setZipResourceTableAsset(const String8& path,
                                                  Asset* asset)
 {
     int idx = getIndex(path);
@@ -1647,6 +1696,26 @@
     return zip->setResourceTableAsset(asset);
 }
 
+ResTable* AssetManager::ZipSet::getZipResourceTable(const String8& path)
+{
+    int idx = getIndex(path);
+    sp<SharedZip> zip = mZipFile[idx];
+    if (zip == NULL) {
+        zip = SharedZip::get(path);
+        mZipFile.editItemAt(idx) = zip;
+    }
+    return zip->getResourceTable();
+}
+
+ResTable* AssetManager::ZipSet::setZipResourceTable(const String8& path,
+                                                    ResTable* res)
+{
+    int idx = getIndex(path);
+    sp<SharedZip> zip = mZipFile[idx];
+    // doesn't make sense to call before previously accessing.
+    return zip->setResourceTable(res);
+}
+
 /*
  * Generate the partial pathname for the specified archive.  The caller
  * gets to prepend the asset root directory.
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 4a5063a..109f28d 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -1136,8 +1136,9 @@
 
 struct ResTable::Header
 {
-    Header() : ownedData(NULL), header(NULL) { }
+    Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL) { }
 
+    ResTable* const                 owner;
     void*                           ownedData;
     const ResTable_header*          header;
     size_t                          size;
@@ -1163,8 +1164,8 @@
 
 struct ResTable::Package
 {
-    Package(const Header* _header, const ResTable_package* _package)
-        : header(_header), package(_package) { }
+    Package(ResTable* _owner, const Header* _header, const ResTable_package* _package)
+        : owner(_owner), header(_header), package(_package) { }
     ~Package()
     {
         size_t i = types.size();
@@ -1174,10 +1175,14 @@
         }
     }
     
+    ResTable* const                 owner;
     const Header* const             header;
     const ResTable_package* const   package;
     Vector<Type*>                   types;
 
+    ResStringPool                   typeStrings;
+    ResStringPool                   keyStrings;
+    
     const Type* getType(size_t idx) const {
         return idx < types.size() ? types[idx] : NULL;
     }
@@ -1188,13 +1193,16 @@
 // table that defined the package); the ones after are skins on top of it.
 struct ResTable::PackageGroup
 {
-    PackageGroup(const String16& _name, uint32_t _id)
-        : name(_name), id(_id), typeCount(0), bags(NULL) { }
+    PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id)
+        : owner(_owner), name(_name), id(_id), typeCount(0), bags(NULL) { }
     ~PackageGroup() {
         clearBagCache();
         const size_t N = packages.size();
         for (size_t i=0; i<N; i++) {
-            delete packages[i];
+            Package* pkg = packages[i];
+            if (pkg->owner == owner) {
+                delete pkg;
+            }
         }
     }
 
@@ -1225,15 +1233,17 @@
         }
     }
     
+    ResTable* const                 owner;
     String16 const                  name;
     uint32_t const                  id;
     Vector<Package*>                packages;
+    
+    // This is for finding typeStrings and other common package stuff.
+    Package*                        basePackage;
 
-    // Taken from the root package.
-    ResStringPool                   typeStrings;
-    ResStringPool                   keyStrings;
+    // For quick access.
     size_t                          typeCount;
-
+    
     // Computed attribute bags, first indexed by the type and second
     // by the entry in that type.
     bag_set***                      bags;
@@ -1560,11 +1570,36 @@
     return add(data, size, cookie, asset, copyData);
 }
 
+status_t ResTable::add(ResTable* src)
+{
+    mError = src->mError;
+    mParams = src->mParams;
+    
+    for (size_t i=0; i<src->mHeaders.size(); i++) {
+        mHeaders.add(src->mHeaders[i]);
+    }
+    
+    for (size_t i=0; i<src->mPackageGroups.size(); i++) {
+        PackageGroup* srcPg = src->mPackageGroups[i];
+        PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id);
+        for (size_t j=0; j<srcPg->packages.size(); j++) {
+            pg->packages.add(srcPg->packages[j]);
+        }
+        pg->basePackage = srcPg->basePackage;
+        pg->typeCount = srcPg->typeCount;
+        mPackageGroups.add(pg);
+    }
+    
+    memcpy(mPackageMap, src->mPackageMap, sizeof(mPackageMap));
+    
+    return mError;
+}
+
 status_t ResTable::add(const void* data, size_t size, void* cookie,
                        Asset* asset, bool copyData)
 {
     if (!data) return NO_ERROR;
-    Header* header = new Header;
+    Header* header = new Header(this);
     header->index = mHeaders.size();
     header->cookie = cookie;
     mHeaders.add(header);
@@ -1682,10 +1717,12 @@
     N = mHeaders.size();
     for (size_t i=0; i<N; i++) {
         Header* header = mHeaders[i];
-        if (header->ownedData) {
-            free(header->ownedData);
+        if (header->owner == this) {
+            if (header->ownedData) {
+                free(header->ownedData);
+            }
+            delete header;
         }
-        delete header;
     }
 
     mPackageGroups.clear();
@@ -1728,8 +1765,8 @@
 
         outName->package = grp->name.string();
         outName->packageLen = grp->name.size();
-        outName->type = grp->typeStrings.stringAt(t, &outName->typeLen);
-        outName->name = grp->keyStrings.stringAt(
+        outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen);
+        outName->name = grp->basePackage->keyStrings.stringAt(
             dtohl(entry->key.index), &outName->nameLen);
         return true;
     }
@@ -2331,13 +2368,13 @@
             continue;
         }
 
-        const ssize_t ti = group->typeStrings.indexOfString(type, typeLen);
+        const ssize_t ti = group->basePackage->typeStrings.indexOfString(type, typeLen);
         if (ti < 0) {
             TABLE_NOISY(printf("Type not found in package %s\n", String8(group->name).string()));
             continue;
         }
 
-        const ssize_t ei = group->keyStrings.indexOfString(name, nameLen);
+        const ssize_t ei = group->basePackage->keyStrings.indexOfString(name, nameLen);
         if (ei < 0) {
             TABLE_NOISY(printf("Name not found in package %s\n", String8(group->name).string()));
             continue;
@@ -3630,25 +3667,36 @@
     PackageGroup* group = NULL;
     uint32_t id = dtohl(pkg->id);
     if (id != 0 && id < 256) {
+    
+        package = new Package(this, header, pkg);
+        if (package == NULL) {
+            return (mError=NO_MEMORY);
+        }
+        
         size_t idx = mPackageMap[id];
         if (idx == 0) {
             idx = mPackageGroups.size()+1;
 
             char16_t tmpName[sizeof(pkg->name)/sizeof(char16_t)];
             strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(char16_t));
-            group = new PackageGroup(String16(tmpName), id);
+            group = new PackageGroup(this, String16(tmpName), id);
             if (group == NULL) {
+                delete package;
                 return (mError=NO_MEMORY);
             }
 
-            err = group->typeStrings.setTo(base+dtohl(pkg->typeStrings),
+            err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
                                            header->dataEnd-(base+dtohl(pkg->typeStrings)));
             if (err != NO_ERROR) {
+                delete group;
+                delete package;
                 return (mError=err);
             }
-            err = group->keyStrings.setTo(base+dtohl(pkg->keyStrings),
+            err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
                                           header->dataEnd-(base+dtohl(pkg->keyStrings)));
             if (err != NO_ERROR) {
+                delete group;
+                delete package;
                 return (mError=err);
             }
 
@@ -3657,6 +3705,8 @@
             if (err < NO_ERROR) {
                 return (mError=err);
             }
+            group->basePackage = package;
+            
             mPackageMap[id] = (uint8_t)idx;
         } else {
             group = mPackageGroups.itemAt(idx-1);
@@ -3664,10 +3714,6 @@
                 return (mError=UNKNOWN_ERROR);
             }
         }
-        package = new Package(header, pkg);
-        if (package == NULL) {
-            return (mError=NO_MEMORY);
-        }
         err = group->packages.add(package);
         if (err < NO_ERROR) {
             return (mError=err);
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 3cd841d..5f1be9d 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -425,8 +425,7 @@
     }
     
     /**
-     * Returns the current playback rate in Hz. Note that this rate may differ from the one set
-     * with {@link #setPlaybackRate(int)} as the value effectively used is implementation-dependent.
+     * Returns the current playback rate in Hz.
      */
     public int getPlaybackRate() {
         return native_get_playback_rate();
@@ -651,18 +650,13 @@
      * Sets the playback sample rate for this track. This sets the sampling rate at which
      * the audio data will be consumed and played back, not the original sampling rate of the
      * content. Setting it to half the sample rate of the content will cause the playback to
-     * last twice as long, but will also result result in a negative pitch shift.
-     * The current implementation supports a maximum sample rate of 64kHz.
-     * Use {@link #getSampleRate()} to check the rate actually used in hardware after 
-     * potential clamping.
+     * last twice as long, but will also result in a negative pitch shift.
+     * The valid sample rate range if from 1Hz to twice the value returned by
+     * {@link #getNativeOutputSampleRate(int)}.
      * @param sampleRateInHz the sample rate expressed in Hz
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
      *    {@link #ERROR_INVALID_OPERATION}
      */
-    // FIXME: the implementation should support twice the hardware output sample rate
-    //   (see {@link #getNativeOutputSampleRate(int)}), but currently
-    //  due to the representation of the sample rate in the native layer, the sample rate
-    //  is limited to 65535Hz
     public int setPlaybackRate(int sampleRateInHz) {
         if (mState != STATE_INITIALIZED) {
             return ERROR_INVALID_OPERATION;
@@ -670,8 +664,7 @@
         if (sampleRateInHz <= 0) {
             return ERROR_BAD_VALUE;
         }
-        native_set_playback_rate(sampleRateInHz);
-        return SUCCESS;
+        return native_set_playback_rate(sampleRateInHz);
     }
 
 
@@ -1031,8 +1024,8 @@
 
     private native final void native_setVolume(float leftVolume, float rightVolume);
 
-    private native final void native_set_playback_rate(int sampleRateInHz);
-    private native final int  native_get_playback_rate();
+    private native final int native_set_playback_rate(int sampleRateInHz);
+    private native final int native_get_playback_rate();
 
     private native final int native_set_marker_pos(int marker);
     private native final int native_get_marker_pos();
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 4c8b02a..e56efbb 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -185,7 +185,6 @@
     mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
     mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
     mCblk->out = 0;
-    mSampleRate = sampleRate;
     mFormat = format;
     // Update buffer size in case it has been limited by AudioFlinger during track creation
     mFrameCount = mCblk->frameCount;
@@ -196,7 +195,7 @@
     mRemainingFrames = notificationFrames;
     mUserData = user;
     // TODO: add audio hardware input latency here
-    mLatency = (1000*mFrameCount) / mSampleRate;
+    mLatency = (1000*mFrameCount) / sampleRate;
     mMarkerPosition = 0;
     mMarkerReached = false;
     mNewPosition = 0;
@@ -218,11 +217,6 @@
     return mLatency;
 }
 
-uint32_t AudioRecord::sampleRate() const
-{
-    return mSampleRate;
-}
-
 int AudioRecord::format() const
 {
     return mFormat;
@@ -321,6 +315,11 @@
     return !mActive;
 }
 
+uint32_t AudioRecord::getSampleRate()
+{
+    return mCblk->sampleRate;
+}
+
 status_t AudioRecord::setMarkerPosition(uint32_t marker)
 {
     if (mCbf == 0) return INVALID_OPERATION;
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 289bd75..b2c067b 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -243,7 +243,6 @@
     mCblk->volume[0] = mCblk->volume[1] = 0x1000;
     mVolume[LEFT] = 1.0f;
     mVolume[RIGHT] = 1.0f;
-    mSampleRate = sampleRate;
     mStreamType = streamType;
     mFormat = format;
     mChannelCount = channelCount;
@@ -254,7 +253,7 @@
     mNotificationFrames = notificationFrames;
     mRemainingFrames = notificationFrames;
     mUserData = user;
-    mLatency = afLatency + (1000*mFrameCount) / mSampleRate;
+    mLatency = afLatency + (1000*mFrameCount) / sampleRate;
     mLoopCount = 0;
     mMarkerPosition = 0;
     mMarkerReached = false;
@@ -281,11 +280,6 @@
     return mStreamType;
 }
 
-uint32_t AudioTrack::sampleRate() const
-{
-    return mSampleRate;
-}
-
 int AudioTrack::format() const
 {
     return mFormat;
@@ -438,24 +432,23 @@
     *right = mVolume[RIGHT];
 }
 
-void AudioTrack::setSampleRate(int rate)
+status_t AudioTrack::setSampleRate(int rate)
 {
     int afSamplingRate;
 
     if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) {
-        return;
+        return NO_INIT;
     }
     // Resampler implementation limits input sampling rate to 2 x output sampling rate.
-    if (rate <= 0) rate = 1;
-    if (rate > afSamplingRate*2) rate = afSamplingRate*2;
-    if (rate > MAX_SAMPLE_RATE) rate = MAX_SAMPLE_RATE;
+    if (rate <= 0 || rate > afSamplingRate*2 ) return BAD_VALUE;
 
-    mCblk->sampleRate = (uint16_t)rate;
+    mCblk->sampleRate = rate;
+    return NO_ERROR;
 }
 
 uint32_t AudioTrack::getSampleRate()
 {
-    return uint32_t(mCblk->sampleRate);
+    return mCblk->sampleRate;
 }
 
 status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
@@ -866,7 +859,7 @@
     result.append(buffer);
     snprintf(buffer, 255, "  format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, mFrameCount);
     result.append(buffer);
-    snprintf(buffer, 255, "  sample rate(%d), status(%d), muted(%d)\n", mSampleRate, mStatus, mMuted);
+    snprintf(buffer, 255, "  sample rate(%d), status(%d), muted(%d)\n", (mCblk == 0) ? 0 : mCblk->sampleRate, mStatus, mMuted);
     result.append(buffer);
     snprintf(buffer, 255, "  active(%d), latency (%d)\n", mActive, mLatency);
     result.append(buffer);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 16be668..f9e98ef 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -166,11 +166,12 @@
             pos += length;
             if (!TextUtils.isEmpty(settingName) && !TextUtils.isEmpty(settingValue)) {
                 //Log.i(TAG, "Restore " + settingName + " = " + settingValue);
-                cv.clear();
-                cv.put(Settings.NameValueTable.NAME, settingName);
-                cv.put(Settings.NameValueTable.VALUE, settingValue);
-                getContentResolver().insert(contentUri, cv);
-                mSettingsHelper.restoreValue(settingName, settingValue);
+                if (mSettingsHelper.restoreValue(settingName, settingValue)) {
+                    cv.clear();
+                    cv.put(Settings.NameValueTable.NAME, settingName);
+                    cv.put(Settings.NameValueTable.VALUE, settingValue);
+                    getContentResolver().insert(contentUri, cv);
+                }
             }
         }
     }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index b065587..5f3fba8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -19,12 +19,13 @@
 import android.backup.BackupDataInput;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.IContentService;
+import android.location.LocationManager;
 import android.media.AudioManager;
 import android.os.IHardwareService;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
-import android.content.IContentService;
 import android.util.Log;
 
 public class SettingsHelper {
@@ -33,10 +34,10 @@
     private Context mContext;
     private AudioManager mAudioManager;
     private IContentService mContentService;
-    private static final String SYNC_AUTO = "auto_sync";
-    private static final String SYNC_MAIL = "gmail-ls_sync";
-    private static final String SYNC_CALENDAR = "calendar_sync";
-    private static final String SYNC_CONTACTS = "contacts_sync";
+    private static final String[] PROVIDERS = { "gmail-ls", "calendar", "contacts" };
+
+    private boolean mSilent;
+    private boolean mVibrate;
 
     public SettingsHelper(Context context) {
         mContext = context;
@@ -45,15 +46,43 @@
         mContentService = ContentResolver.getContentService();
     }
 
-    public void restoreValue(String name, String value) {
+    /**
+     * Sets the property via a call to the appropriate API, if any, and returns
+     * whether or not the setting should be saved to the database as well.
+     * @param name the name of the setting
+     * @param value the string value of the setting
+     * @return whether to continue with writing the value to the database. In
+     * some cases the data will be written by the call to the appropriate API,
+     * and in some cases the property value needs to be modified before setting.
+     */
+    public boolean restoreValue(String name, String value) {
         if (Settings.System.SCREEN_BRIGHTNESS.equals(name)) {
             setBrightness(Integer.parseInt(value));
         } else if (Settings.System.SOUND_EFFECTS_ENABLED.equals(name)) {
-            if (Integer.parseInt(value) == 1) {
-                mAudioManager.loadSoundEffects();
-            } else {
-                mAudioManager.unloadSoundEffects();
-            }
+            setSoundEffects(Integer.parseInt(value) == 1);
+        } else if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
+            setGpsLocation(value);
+            return false;
+        }
+        return true;
+    }
+
+    private void setGpsLocation(String value) {
+        final String GPS = LocationManager.GPS_PROVIDER;
+        boolean enabled = 
+                GPS.equals(value) ||
+                value.startsWith(GPS + ",") ||
+                value.endsWith("," + GPS) ||
+                value.contains("," + GPS + ",");
+        Settings.Secure.setLocationProviderEnabled(
+                mContext.getContentResolver(), GPS, enabled);
+    }
+
+    private void setSoundEffects(boolean enable) {
+        if (enable) {
+            mAudioManager.loadSoundEffects();
+        } else {
+            mAudioManager.unloadSoundEffects();
         }
     }
 
@@ -69,8 +98,19 @@
         }
     }
 
-    static final String[] PROVIDERS = { "gmail-ls", "calendar", "contacts" };
-    
+    private void setRingerMode() {
+        if (mSilent) {
+            mAudioManager.setRingerMode(mVibrate ? AudioManager.RINGER_MODE_VIBRATE :
+                AudioManager.RINGER_MODE_SILENT);
+        } else {
+            mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+            mAudioManager.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,
+                    mVibrate ? AudioManager.VIBRATE_SETTING_ON
+                            : AudioManager.VIBRATE_SETTING_OFF);
+        }
+    }
+
+    /* TODO: Get a list of all sync providers and save/restore the settings */
     byte[] getSyncProviders() {
         byte[] sync = new byte[1 + PROVIDERS.length];
         try {
@@ -85,7 +125,7 @@
         }
         return sync;
     }
-    
+
     void setSyncProviders(BackupDataInput backup) {
         byte[] sync = new byte[backup.getDataSize()];
 
diff --git a/packages/TtsService/AndroidManifest.xml b/packages/TtsService/AndroidManifest.xml
index fab2534..bd17ba0 100755
--- a/packages/TtsService/AndroidManifest.xml
+++ b/packages/TtsService/AndroidManifest.xml
@@ -6,7 +6,7 @@
                  android:name=".TtsService"
                  android:label="TTS Service">
             <intent-filter>
-                <action android:name="android.intent.action.USE_TTS"/>
+                <action android:name="android.intent.action.START_TTS_SERVICE"/>
                 <category android:name="android.intent.category.TTS"/>
             </intent-filter>
         </service>
diff --git a/packages/TtsService/src/android/tts/SynthProxy.java b/packages/TtsService/src/android/tts/SynthProxy.java
index 11a4380..bb16b14 100755
--- a/packages/TtsService/src/android/tts/SynthProxy.java
+++ b/packages/TtsService/src/android/tts/SynthProxy.java
@@ -45,15 +45,15 @@
     /**
      * Stops and clears the AudioTrack.
      */
-    public void stop() {
-        native_stop(mJniData);
+    public int stop() {
+        return native_stop(mJniData);
     }
 
     /**
      * Synthesize speech and speak it directly using AudioTrack.
      */
-    public void speak(String text) {
-        native_speak(mJniData, text);
+    public int speak(String text) {
+        return native_speak(mJniData, text);
     }
 
     /**
@@ -61,12 +61,10 @@
      * WAV file to the given path, assuming it is writable. Something like
      * "/sdcard/???.wav" is recommended.
      */
-    public void synthesizeToFile(String text, String filename) {
-        native_synthesizeToFile(mJniData, text, filename);
+    public int synthesizeToFile(String text, String filename) {
+        return native_synthesizeToFile(mJniData, text, filename);
     }
 
-    // TODO add IPA methods
-
     /**
      * Queries for language support.
      * Return codes are defined in android.speech.tts.TextToSpeech
@@ -78,29 +76,29 @@
     /**
      * Sets the language.
      */
-    public void setLanguage(String language, String country, String variant) {
-        native_setLanguage(mJniData, language, country, variant);
+    public int setLanguage(String language, String country, String variant) {
+        return native_setLanguage(mJniData, language, country, variant);
     }
 
     /**
      * Loads the language: it's not set, but prepared for use later.
      */
-    public void loadLanguage(String language, String country, String variant) {
-        native_loadLanguage(mJniData, language, country, variant);
+    public int loadLanguage(String language, String country, String variant) {
+        return native_loadLanguage(mJniData, language, country, variant);
     }
 
     /**
      * Sets the speech rate.
      */
-    public final void setSpeechRate(int speechRate) {
-        native_setSpeechRate(mJniData, speechRate);
+    public final int setSpeechRate(int speechRate) {
+        return native_setSpeechRate(mJniData, speechRate);
     }
 
     /**
      * Sets the pitch of the synthesized voice.
      */
-    public final void setPitch(int pitch) {
-        native_setPitch(mJniData, pitch);
+    public final int setPitch(int pitch) {
+        return native_setPitch(mJniData, pitch);
     }
 
     /**
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index 5c0c55c..10f4d6e 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -36,6 +36,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.concurrent.locks.ReentrantLock;
 
 /**
@@ -102,7 +103,7 @@
     private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000;
     private static final int MAX_FILENAME_LENGTH = 250;
 
-    private static final String ACTION = "android.intent.action.USE_TTS";
+    private static final String ACTION = "android.intent.action.START_TTS_SERVICE";
     private static final String CATEGORY = "android.intent.category.TTS";
     private static final String PKGNAME = "android.tts";
 
@@ -183,7 +184,8 @@
         String defaultLang = android.provider.Settings.Secure.getString(mResolver,
                 android.provider.Settings.Secure.TTS_DEFAULT_LANG);
         if (defaultLang == null) {
-            return TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_LANG;
+            // no setting found, use the current Locale to determine the default language
+            return Locale.getDefault().getISO3Language();
         } else {
             return defaultLang;
         }
@@ -194,7 +196,8 @@
         String defaultCountry = android.provider.Settings.Secure.getString(mResolver,
                 android.provider.Settings.Secure.TTS_DEFAULT_COUNTRY);
         if (defaultCountry == null) {
-            return TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_COUNTRY;
+            // no setting found, use the current Locale to determine the default country
+            return Locale.getDefault().getISO3Country();
         } else {
             return defaultCountry;
         }
@@ -205,24 +208,25 @@
         String defaultVar = android.provider.Settings.Secure.getString(mResolver,
                 android.provider.Settings.Secure.TTS_DEFAULT_VARIANT);
         if (defaultVar == null) {
-            return TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT;
+            // no setting found, use the current Locale to determine the default variant
+            return Locale.getDefault().getVariant();
         } else {
             return defaultVar;
         }
     }
 
 
-    private void setSpeechRate(int rate) {
+    private int setSpeechRate(int rate) {
         if (isDefaultEnforced()) {
-            nativeSynth.setSpeechRate(getDefaultRate());
+            return nativeSynth.setSpeechRate(getDefaultRate());
         } else {
-            nativeSynth.setSpeechRate(rate);
+            return nativeSynth.setSpeechRate(rate);
         }
     }
 
 
-    private void setPitch(int pitch) {
-        nativeSynth.setPitch(pitch);
+    private int setPitch(int pitch) {
+        return nativeSynth.setPitch(pitch);
     }
 
 
@@ -237,13 +241,13 @@
     }
 
 
-    private void setLanguage(String lang, String country, String variant) {
+    private int setLanguage(String lang, String country, String variant) {
         Log.v("TTS", "TtsService.setLanguage(" + lang + ", " + country + ", " + variant + ")");
         if (isDefaultEnforced()) {
-            nativeSynth.setLanguage(getDefaultLanguage(), getDefaultCountry(),
+            return nativeSynth.setLanguage(getDefaultLanguage(), getDefaultCountry(),
                     getDefaultLocVariant());
         } else {
-            nativeSynth.setLanguage(lang, country, variant);
+            return nativeSynth.setLanguage(lang, country, variant);
         }
     }
 
@@ -314,7 +318,7 @@
      *            An ArrayList of parameters. This is not implemented for all
      *            engines.
      */
-    private void speak(String text, int queueMode, ArrayList<String> params) {
+    private int speak(String text, int queueMode, ArrayList<String> params) {
         if (queueMode == 0) {
             stop();
         }
@@ -322,6 +326,7 @@
         if (!mIsSpeaking) {
             processSpeechQueue();
         }
+        return TextToSpeech.TTS_SUCCESS;
     }
 
     /**
@@ -336,7 +341,7 @@
      *            An ArrayList of parameters. This is not implemented for all
      *            engines.
      */
-    private void playEarcon(String earcon, int queueMode,
+    private int playEarcon(String earcon, int queueMode,
             ArrayList<String> params) {
         if (queueMode == 0) {
             stop();
@@ -345,16 +350,17 @@
         if (!mIsSpeaking) {
             processSpeechQueue();
         }
+        return TextToSpeech.TTS_SUCCESS;
     }
 
     /**
      * Stops all speech output and removes any utterances still in the queue.
      */
-    private void stop() {
+    private int stop() {
         Log.i("TTS", "Stopping");
         mSpeechQueue.clear();
 
-        nativeSynth.stop();
+        int result = nativeSynth.stop();
         mIsSpeaking = false;
         if (mPlayer != null) {
             try {
@@ -364,13 +370,14 @@
             }
         }
         Log.i("TTS", "Stopped");
+        return result;
     }
 
     public void onCompletion(MediaPlayer arg0) {
         processSpeechQueue();
     }
 
-    private void playSilence(long duration, int queueMode,
+    private int playSilence(long duration, int queueMode,
             ArrayList<String> params) {
         if (queueMode == 0) {
             stop();
@@ -379,6 +386,7 @@
         if (!mIsSpeaking) {
             processSpeechQueue();
         }
+        return TextToSpeech.TTS_SUCCESS;
     }
 
     private void silence(final long duration) {
@@ -725,12 +733,12 @@
          *            An ArrayList of parameters. The first element of this
          *            array controls the type of voice to use.
          */
-        public void speak(String text, int queueMode, String[] params) {
+        public int speak(String text, int queueMode, String[] params) {
             ArrayList<String> speakingParams = new ArrayList<String>();
             if (params != null) {
                 speakingParams = new ArrayList<String>(Arrays.asList(params));
             }
-            mSelf.speak(text, queueMode, speakingParams);
+            return mSelf.speak(text, queueMode, speakingParams);
         }
 
         /**
@@ -744,12 +752,12 @@
          * @param params
          *            An ArrayList of parameters.
          */
-        public void playEarcon(String earcon, int queueMode, String[] params) {
+        public int playEarcon(String earcon, int queueMode, String[] params) {
             ArrayList<String> speakingParams = new ArrayList<String>();
             if (params != null) {
                 speakingParams = new ArrayList<String>(Arrays.asList(params));
             }
-            mSelf.playEarcon(earcon, queueMode, speakingParams);
+            return mSelf.playEarcon(earcon, queueMode, speakingParams);
         }
 
         /**
@@ -763,20 +771,20 @@
          * @param params
          *            An ArrayList of parameters.
          */
-        public void playSilence(long duration, int queueMode, String[] params) {
+        public int playSilence(long duration, int queueMode, String[] params) {
             ArrayList<String> speakingParams = new ArrayList<String>();
             if (params != null) {
                 speakingParams = new ArrayList<String>(Arrays.asList(params));
             }
-            mSelf.playSilence(duration, queueMode, speakingParams);
+            return mSelf.playSilence(duration, queueMode, speakingParams);
         }
 
         /**
          * Stops all speech output and removes any utterances still in the
          * queue.
          */
-        public void stop() {
-            mSelf.stop();
+        public int stop() {
+            return mSelf.stop();
         }
 
         /**
@@ -849,8 +857,8 @@
          * @param speechRate
          *            The speech rate that should be used
          */
-        public void setSpeechRate(int speechRate) {
-            mSelf.setSpeechRate(speechRate);
+        public int setSpeechRate(int speechRate) {
+            return mSelf.setSpeechRate(speechRate);
         }
 
         /**
@@ -860,8 +868,8 @@
          * @param pitch
          *            The pitch that should be used for the synthesized voice
          */
-        public void setPitch(int pitch) {
-            mSelf.setPitch(pitch);
+        public int setPitch(int pitch) {
+            return mSelf.setPitch(pitch);
         }
 
         /**
@@ -895,8 +903,8 @@
          * @param country  the three letter ISO country code.
          * @param variant  the variant code associated with the country and language pair.
          */
-        public void setLanguage(String lang, String country, String variant) {
-            mSelf.setLanguage(lang, country, variant);
+        public int setLanguage(String lang, String country, String variant) {
+            return mSelf.setLanguage(lang, country, variant);
         }
 
         /**
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index e47d853..2ae9fc5 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -81,6 +81,10 @@
     // trigger an immediate pass.
     private static final long BACKUP_INTERVAL = AlarmManager.INTERVAL_HOUR;
 
+    // The amount of time between the initial provisioning of the device and
+    // the first backup pass.
+    private static final long FIRST_BACKUP_INTERVAL = 12 * AlarmManager.INTERVAL_HOUR;
+
     private static final String RUN_BACKUP_ACTION = "_backup_run_";
     private static final int MSG_RUN_BACKUP = 1;
     private static final int MSG_RUN_FULL_BACKUP = 2;
@@ -97,6 +101,7 @@
     private AlarmManager mAlarmManager;
 
     private boolean mEnabled;   // access to this is synchronized on 'this'
+    private boolean mProvisioned;
     private PowerManager.WakeLock mWakelock;
     private final BackupHandler mBackupHandler = new BackupHandler();
     private PendingIntent mRunBackupIntent;
@@ -188,6 +193,9 @@
         // Set up our bookkeeping
         boolean areEnabled = Settings.Secure.getInt(context.getContentResolver(),
                 Settings.Secure.BACKUP_ENABLED, 0) != 0;
+        // !!! TODO: mProvisioned needs to default to 0, not 1.
+        mProvisioned = Settings.Secure.getInt(context.getContentResolver(),
+                Settings.Secure.BACKUP_PROVISIONED, 1) != 0;
         mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
         mDataDir = Environment.getDownloadCacheDirectory();
 
@@ -316,6 +324,7 @@
     // Add a transport to our set of available backends
     private void registerTransport(String name, IBackupTransport transport) {
         synchronized (mTransports) {
+            if (DEBUG) Log.v(TAG, "Registering transport " + name + " = " + transport);
             mTransports.put(name, transport);
         }
     }
@@ -1300,7 +1309,7 @@
         }
     }
 
-    // Enable/disable the backup transport
+    // Enable/disable the backup service
     public void setBackupEnabled(boolean enable) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "setBackupEnabled");
@@ -1313,11 +1322,9 @@
         }
 
         synchronized (mQueueLock) {
-            if (enable && !wasEnabled) {
+            if (enable && !wasEnabled && mProvisioned) {
                 // if we've just been enabled, start scheduling backup passes
-                long when = System.currentTimeMillis() + BACKUP_INTERVAL;
-                mAlarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, when,
-                        BACKUP_INTERVAL, mRunBackupIntent);
+                startBackupAlarmsLocked(BACKUP_INTERVAL);
             } else if (!enable) {
                 // No longer enabled, so stop running backups
                 mAlarmManager.cancel(mRunBackupIntent);
@@ -1325,6 +1332,36 @@
         }
     }
 
+    // Mark the backup service as having been provisioned
+    public void setBackupProvisioned(boolean available) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+                "setBackupProvisioned");
+
+        boolean wasProvisioned = mProvisioned;
+        synchronized (this) {
+            Settings.Secure.putInt(mContext.getContentResolver(),
+                    Settings.Secure.BACKUP_PROVISIONED, available ? 1 : 0);
+            mProvisioned = available;
+        }
+
+        synchronized (mQueueLock) {
+            if (available && !wasProvisioned && mEnabled) {
+                // we're now good to go, so start the backup alarms
+                startBackupAlarmsLocked(FIRST_BACKUP_INTERVAL);
+            } else if (!available) {
+                // No longer enabled, so stop running backups
+                Log.w(TAG, "Backup service no longer provisioned");
+                mAlarmManager.cancel(mRunBackupIntent);
+            }
+        }
+    }
+
+    private void startBackupAlarmsLocked(long delayBeforeFirstBackup) {
+        long when = System.currentTimeMillis() + delayBeforeFirstBackup;
+        mAlarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, when,
+                BACKUP_INTERVAL, mRunBackupIntent);
+    }
+
     // Report whether the backup mechanism is currently enabled
     public boolean isBackupEnabled() {
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
@@ -1341,7 +1378,7 @@
 
     // Report all known, available backup transports
     public String[] listAllTransports() {
-        mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "listAllTransports");
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "listAllTransports");
 
         String[] list = null;
         ArrayList<String> known = new ArrayList<String>();
@@ -1503,7 +1540,10 @@
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         synchronized (mQueueLock) {
-            pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled"));
+            long oldId = Binder.clearCallingIdentity();
+
+            pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
+                    + " / " + (!mProvisioned ? "not " : "") + "provisioned");
             pw.println("Available transports:");
             for (String t : listAllTransports()) {
                 String pad = (t.equals(mCurrentTransport)) ? "  * " : "    ";
@@ -1524,6 +1564,8 @@
             for (BackupRequest req : mPendingBackups.values()) {
                 pw.println("    " + req);
             }
+
+            Binder.restoreCallingIdentity(oldId);
         }
     }
 }
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 0f5b3fd..fab97b1 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -648,14 +648,14 @@
 
     private void checkPermissionsSafe(String provider) {
         if (LocationManager.GPS_PROVIDER.equals(provider)
-            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
+            && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)) {
             throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
         }
         if (LocationManager.NETWORK_PROVIDER.equals(provider)
-            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
+            && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)
-            && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
+            && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)) {
             throw new SecurityException(
                 "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
@@ -664,14 +664,14 @@
 
     private boolean isAllowedProviderSafe(String provider) {
         if (LocationManager.GPS_PROVIDER.equals(provider)
-            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
+            && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)) {
             return false;
         }
         if (LocationManager.NETWORK_PROVIDER.equals(provider)
-            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
+            && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)
-            && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
+            && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)) {
             return false;
         }
@@ -1075,7 +1075,7 @@
         if (mGpsStatusProvider == null) {
             return false;
         }
-        if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) !=
+        if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
                 PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
         }
@@ -1103,7 +1103,7 @@
         // first check for permission to the provider
         checkPermissionsSafe(provider);
         // and check for ACCESS_LOCATION_EXTRA_COMMANDS
-        if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
+        if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
                 != PackageManager.PERMISSION_GRANTED)) {
             throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
         }
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index e2aee42..a940af3 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -38,6 +38,7 @@
 import android.net.wifi.WifiStateTracker;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SupplicantState;
 import android.net.NetworkStateTracker;
 import android.net.DhcpInfo;
 import android.os.Binder;
@@ -1569,8 +1570,9 @@
                  * or plugged in to AC).
                  */
                 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
-                    if (!mWifiStateTracker.hasIpAddress()) {
-                        // do not keep Wifi awake when screen is off if Wifi is not fully active
+                    WifiInfo info = mWifiStateTracker.requestConnectionInfo();
+                    if (info.getSupplicantState() != SupplicantState.COMPLETED) {
+                        // do not keep Wifi awake when screen is off if Wifi is not associated
                         mDeviceIdle = true;
                         updateWifiState();
                     } else {
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 eaeda64..ef3afff 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -455,7 +455,14 @@
         }
     }
 
-    private static byte[] encode7bitGsm(String msg)
+    private static int calcUdhSeptetPadding(int userDataHeaderLen) {
+        int udhBits = userDataHeaderLen * 8;
+        int udhSeptets = (udhBits + 6) / 7;
+        int paddingBits = (udhSeptets * 7) - udhBits;
+        return paddingBits;
+    }
+
+    private static byte[] encode7bitGsm(String msg, int paddingBits)
         throws CodingException
     {
         try {
@@ -464,11 +471,9 @@
              * an option to produce just the data without prepending
              * the length.
              */
-            byte []fullData = GsmAlphabet.stringToGsm7BitPacked(msg);
+            byte []fullData = GsmAlphabet.stringToGsm7BitPacked(msg, 0, -1, paddingBits, true);
             byte []data = new byte[fullData.length - 1];
-            for (int i = 0; i < data.length; i++) {
-                data[i] = fullData[i + 1];
-            }
+            System.arraycopy(fullData, 1, data, 0, fullData.length - 1);
             return data;
         } catch (com.android.internal.telephony.EncodeException ex) {
             throw new CodingException("7bit GSM encode failed: " + ex);
@@ -478,9 +483,11 @@
     private static void encodeUserDataPayload(UserData uData)
         throws CodingException
     {
+        // TODO(cleanup): UDH can only occur in EMS mode, meaning
+        // encapsulation of GSM encoding, and so the logic here should
+        // be refactored to more cleanly reflect this constraint.
+
         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
 
@@ -502,8 +509,9 @@
                     uData.payloadStr = "";
                 }
                 if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
-                    payloadData = encode7bitGsm(uData.payloadStr);
-                    codeUnitCount = (payloadData.length * 8) / 7;
+                    int paddingBits = calcUdhSeptetPadding(headerDataLen);
+                    payloadData = encode7bitGsm(uData.payloadStr, paddingBits);
+                    codeUnitCount = ((payloadData.length + headerDataLen) * 8) / 7;
                 } else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) {
                     payloadData = encode7bitAscii(uData.payloadStr, true);
                     codeUnitCount = uData.payloadStr.length();
@@ -528,8 +536,9 @@
                 } 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;
+                    int paddingBits = calcUdhSeptetPadding(headerDataLen);
+                    payloadData = encode7bitGsm(uData.payloadStr, paddingBits);
+                    codeUnitCount = ((payloadData.length + headerDataLen) * 8) / 7;
                     uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
                 }
             } catch (CodingException ex) {
@@ -880,7 +889,12 @@
     private static String decode7bitGsm(byte[] data, int offset, int numFields)
         throws CodingException
     {
-        String result = GsmAlphabet.gsm7BitPackedToString(data, offset, numFields);
+        int paddingBits = calcUdhSeptetPadding(offset);
+        numFields -= (((offset * 8) + paddingBits) / 7);
+        // TODO: It seems wrong that only Gsm7 bit encodings would
+        // take into account the header in numFields calculations.
+        // This should be verified.
+        String result = GsmAlphabet.gsm7BitPackedToString(data, offset, numFields, paddingBits);
         if (result == null) {
             throw new CodingException("7bit GSM decoding failed");
         }
diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/android/test/mock/MockContext.java
index efc4880..b83a44d6 100644
--- a/test-runner/android/test/mock/MockContext.java
+++ b/test-runner/android/test/mock/MockContext.java
@@ -397,4 +397,9 @@
             throws PackageManager.NameNotFoundException {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public boolean isRestricted() {
+        throw new UnsupportedOperationException();        
+    }
 }
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
index 2ff0a6a..f0ba573 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
@@ -108,6 +108,21 @@
         userData.payloadStr = "More @ testing\nis great^|^~woohoo";
         revBearerData = BearerData.decode(BearerData.encode(bearerData));
         assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+        SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
+        concatRef.refNumber = 0xEE;
+        concatRef.msgCount = 2;
+        concatRef.seqNumber = 2;
+        concatRef.isEightBits = true;
+        SmsHeader smsHeader = new SmsHeader();
+        smsHeader.concatRef = concatRef;
+        byte[] encodedHeader = SmsHeader.toByteArray(smsHeader);
+        userData.userDataHeader = smsHeader;
+        revBearerData = BearerData.decode(BearerData.encode(bearerData));
+        assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+        SmsHeader decodedHeader = revBearerData.userData.userDataHeader;
+        assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber);
+        assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount);
+        assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber);
     }
 
     @SmallTest
diff --git a/tests/backup/src/com/android/backuptest/BackupTestActivity.java b/tests/backup/src/com/android/backuptest/BackupTestActivity.java
index 7f30c91..afbc703 100644
--- a/tests/backup/src/com/android/backuptest/BackupTestActivity.java
+++ b/tests/backup/src/com/android/backuptest/BackupTestActivity.java
@@ -52,6 +52,8 @@
     static final String PREF_KEY = "pref";
     static final String FILE_NAME = "file.txt";
 
+    BackupManager sBm = new BackupManager(this);
+
     Test[] mTests = new Test[] {
         new Test("Show File") {
             void run() {
@@ -85,8 +87,7 @@
                         output.close();
                     }
                 }
-                BackupManager bm = new BackupManager(BackupTestActivity.this);
-                bm.dataChanged();
+                sBm.dataChanged();
             }
         },
         new Test("Clear File") {
@@ -100,14 +101,12 @@
                         output.close();
                     }
                 }
-                BackupManager bm = new BackupManager(BackupTestActivity.this);
-                bm.dataChanged();
+                sBm.dataChanged();
             }
         },
         new Test("Poke") {
             void run() {
-                BackupManager bm = new BackupManager(BackupTestActivity.this);
-                bm.dataChanged();
+                sBm.dataChanged();
             }
         },
         new Test("Show Shared Pref") {
@@ -126,8 +125,7 @@
                 SharedPreferences.Editor editor = prefs.edit();
                 editor.putInt(PREF_KEY, val+1);
                 editor.commit();
-                BackupManager bm = new BackupManager(BackupTestActivity.this);
-                bm.dataChanged();
+                sBm.dataChanged();
             }
         },
         new Test("Backup Helpers") {