Merge change 6382

* changes:
  add a virtual destructor to region_rasterizer, to be on the safe side
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index afda98d..b624402 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;
@@ -151,6 +153,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();
@@ -1254,7 +1257,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);
@@ -1356,6 +1359,19 @@
             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;
             }
         }
@@ -1475,7 +1491,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/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/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 fca318e..5f90071 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2693,6 +2693,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/util/EventLog.java b/core/java/android/util/EventLog.java
index 7c87248..0f0be79 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -73,7 +73,7 @@
  *   </ul>
  * </li>
  * <li> '\n': 1 byte - an automatically generated newline, used to help detect and recover from log
- *                     corruption and enable stansard unix tools like grep, tail and wc to operate
+ *                     corruption and enable standard unix tools like grep, tail and wc to operate
  *                     on event logs. </li>
  * </ul>
  *
@@ -289,4 +289,13 @@
      */
     public static native void readEvents(int[] tags, Collection<Event> output)
             throws IOException;
+
+    /**
+     * Read events from a file.
+     * @param path to read from
+     * @param output container to add events into
+     * @throws IOException if something goes wrong reading events
+     */
+    public static native void readEvents(String path, Collection<Event> output)
+            throws IOException;
 }
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index a12b14a..41cc86a 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -553,13 +553,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 b2f2e51..899d636 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3024,7 +3024,12 @@
      */
     /* package */ void deleteSelection(int start, int end) {
         mTextGeneration++;
-        mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, start, end);
+        WebViewCore.DeleteSelectionData data
+                = new WebViewCore.DeleteSelectionData();
+        data.mStart = start;
+        data.mEnd = end;
+        data.mTextGeneration = mTextGeneration;
+        mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, data);
     }
 
     /**
@@ -4672,6 +4677,7 @@
         arg.mNewStart = newStart;
         arg.mNewEnd = newEnd;
         mTextGeneration++;
+        arg.mTextGeneration = mTextGeneration;
         mWebViewCore.sendMessage(EventHub.REPLACE_TEXT, oldStart, oldEnd, arg);
     }
 
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 44d8b7e..20f7239 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -370,7 +370,8 @@
 
     // Start: functions that deal with text editing
     private native void nativeReplaceTextfieldText(
-            int oldStart, int oldEnd, String replace, int newStart, int newEnd);
+            int oldStart, int oldEnd, String replace, int newStart, int newEnd,
+            int textGeneration);
 
     private native void passToJs(int gen,
             String currentText, int keyCode, int keyValue, boolean down,
@@ -415,8 +416,10 @@
      *  order, swap them.
      *  @param  start   Beginning of selection to delete.
      *  @param  end     End of selection to delete.
+     *  @param  textGeneration Text generation number when delete was pressed.
      */
-    private native void nativeDeleteSelection(int start, int end);
+    private native void nativeDeleteSelection(int start, int end,
+            int textGeneration);
 
     /**
      *  Set the selection to (start, end) in the focused textfield. If start and
@@ -551,10 +554,17 @@
         byte[] mPostData;
     }
 
+    static class DeleteSelectionData {
+        int mStart;
+        int mEnd;
+        int mTextGeneration;
+    }
+
     static class ReplaceTextData {
         String mReplace;
         int mNewStart;
         int mNewEnd;
+        int mTextGeneration;
     }
 
     static class TouchUpData {
@@ -920,7 +930,8 @@
                         case REPLACE_TEXT:
                             ReplaceTextData rep = (ReplaceTextData) msg.obj;
                             nativeReplaceTextfieldText(msg.arg1, msg.arg2,
-                                    rep.mReplace, rep.mNewStart, rep.mNewEnd);
+                                    rep.mReplace, rep.mNewStart, rep.mNewEnd,
+                                    rep.mTextGeneration);
                             break;
 
                         case PASS_TO_JS: {
@@ -1029,7 +1040,11 @@
                             break;
 
                         case DELETE_SELECTION:
-                            nativeDeleteSelection(msg.arg1, msg.arg2);
+                            DeleteSelectionData deleteSelectionData
+                                    = (DeleteSelectionData) msg.obj;
+                            nativeDeleteSelection(deleteSelectionData.mStart,
+                                    deleteSelectionData.mEnd,
+                                    deleteSelectionData.mTextGeneration);
                             break;
 
                         case SET_SELECTION:
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 0cce3a6..cf3ba7f 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/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 5e5103a..34b7c89 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -51,17 +51,17 @@
     size_t len;
     size_t capacity;
     uint8_t* buf;
-    
+
     ByteBuf(size_t initSize) {
         buf = (uint8_t*)malloc(initSize);
         len = 0;
-        capacity = initSize;        
+        capacity = initSize;
     }
-    
+
     ~ByteBuf() {
         free(buf);
     }
-    
+
     bool ensureExtraCapacity(size_t extra) {
         size_t spaceNeeded = len + extra;
         if (spaceNeeded > capacity) {
@@ -77,7 +77,7 @@
             return true;
         }
     }
- 
+
     void putIntEvent(jint value) {
         bool succeeded = ensureExtraCapacity(INT_BUFFER_SIZE);
         buf[len++] = EVENT_TYPE_INT;
@@ -162,7 +162,7 @@
  * In class android.util.EventLog:
  *  static native int writeEvent(long tag, long value)
  */
-static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz, 
+static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz,
                                                   jint tag, jlong value)
 {
     return android_btWriteLog(tag, EVENT_TYPE_LONG, &value, sizeof(value));
@@ -210,6 +210,8 @@
 /*
  * In class android.util.EventLog:
  *  static native void readEvents(int[] tags, Collection<Event> output)
+ *
+ *  Reads events from the event log, typically /dev/log/events
  */
 static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz,
                                              jintArray tags,
@@ -273,6 +275,80 @@
     env->ReleaseIntArrayElements(tags, tagValues, 0);
 }
 
+/*
+ * In class android.util.EventLog:
+ *  static native void readEvents(String path, Collection<Event> output)
+ *
+ *  Reads events from a file (See Checkin.Aggregation). Events are stored in
+ *  native raw format (logger_entry + payload).
+ */
+static void android_util_EventLog_readEventsFile(JNIEnv* env, jobject clazz, jstring path,
+            jobject out) {
+    if (path == NULL || out == NULL) {
+        jniThrowException(env, "java/lang/NullPointerException", NULL);
+        return;
+    }
+
+    const char *pathString = env->GetStringUTFChars(path, 0);
+    int fd = open(pathString, O_RDONLY | O_NONBLOCK);
+    env->ReleaseStringUTFChars(path, pathString);
+
+    if (fd < 0) {
+        jniThrowIOException(env, errno);
+        return;
+    }
+
+    uint8_t buf[LOGGER_ENTRY_MAX_LEN];
+    for (;;) {
+        // read log entry structure from file
+        int len = read(fd, buf, sizeof(logger_entry));
+        if (len == 0) {
+            break; // end of file
+        } else if (len < 0) {
+            jniThrowIOException(env, errno);
+        } else if ((size_t) len < sizeof(logger_entry)) {
+            jniThrowException(env, "java/io/IOException", "Event header too short");
+            break;
+        }
+
+        // read event payload
+        logger_entry* entry = (logger_entry*) buf;
+        if (entry->len > LOGGER_ENTRY_MAX_PAYLOAD) {
+            jniThrowException(env,
+                    "java/lang/IllegalArgumentException",
+                    "Too much data for event payload. Corrupt file?");
+            break;
+        }
+
+        len = read(fd, buf + sizeof(logger_entry), entry->len);
+        if (len == 0) {
+            break; // end of file
+        } else if (len < 0) {
+            jniThrowIOException(env, errno);
+        } else if ((size_t) len < entry->len) {
+            jniThrowException(env, "java/io/IOException", "Event payload too short");
+            break;
+        }
+
+        // create EventLog$Event and add it to the collection
+        int buffer_size = sizeof(logger_entry) + entry->len;
+        jbyteArray array = env->NewByteArray(buffer_size);
+        if (array == NULL) break;
+
+        jbyte *bytes = env->GetByteArrayElements(array, NULL);
+        memcpy(bytes, buf, buffer_size);
+        env->ReleaseByteArrayElements(array, bytes, 0);
+
+        jobject event = env->NewObject(gEventClass, gEventInitID, array);
+        if (event == NULL) break;
+
+        env->CallBooleanMethod(out, gCollectionAddID, event);
+        env->DeleteLocalRef(event);
+        env->DeleteLocalRef(array);
+    }
+
+    close(fd);
+}
 
 /*
  * JNI registration.
@@ -292,6 +368,10 @@
     { "readEvents",
       "([ILjava/util/Collection;)V",
       (void*) android_util_EventLog_readEvents
+    },
+    { "readEvents",
+      "(Ljava/lang/String;Ljava/util/Collection;)V",
+      (void*) android_util_EventLog_readEventsFile
     }
 };
 
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/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 106807e..83ff508 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 0955819..2e1fbda 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/List.h b/include/utils/List.h
index 4041a89..403cd7f 100644
--- a/include/utils/List.h
+++ b/include/utils/List.h
@@ -154,9 +154,9 @@
 
         inline _NodePtr getNode() const { return mpNode; }
 
+        _NodePtr mpNode;    /* should be private, but older gcc fails */
     private:
         friend class List;
-        _NodePtr mpNode;
     };
 
 public:
diff --git a/libs/audioflinger/AudioBufferProvider.h b/libs/audioflinger/AudioBufferProvider.h
index 1a467c7..81c5c39 100644
--- a/libs/audioflinger/AudioBufferProvider.h
+++ b/libs/audioflinger/AudioBufferProvider.h
@@ -36,6 +36,8 @@
         };
         size_t frameCount;
     };
+
+    virtual ~AudioBufferProvider() {}
     
     virtual status_t getNextBuffer(Buffer* buffer) = 0;
     virtual void releaseBuffer(Buffer* buffer) = 0;
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index a5b91f6..82289dd 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -1288,7 +1288,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;
@@ -1603,8 +1603,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));
@@ -1627,8 +1627,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
@@ -1689,7 +1689,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 {
@@ -2274,12 +2274,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/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 cf0965e..0a6f4f7 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 4a1b69e..af7dae5 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/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index 0bed72bd..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;
 
 /**
@@ -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,7 +208,8 @@
         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;
         }
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 ab6e49c1..9da29fa 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;
@@ -1577,8 +1578,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/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") {