Merge change I60413727 into eclair

* changes:
  Fix issue #2226370: Resource versions match with equality
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 697ac76..8faef59ba 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -96,6 +96,10 @@
     
     // The extra key used in an intent to the speech recognizer for in-app voice search.
     private static final String EXTRA_CALLING_PACKAGE = "calling_package";
+    
+    // The string used for privateImeOptions to identify to the IME that it should not show
+    // a microphone button since one already exists in the search dialog.
+    private static final String IME_OPTION_NO_MICROPHONE = "nm";
 
     private static final int SEARCH_PLATE_LEFT_PADDING_GLOBAL = 12;
     private static final int SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL = 7;
@@ -543,6 +547,14 @@
             mSearchAutoComplete.setInputType(inputType);
             mSearchAutoCompleteImeOptions = mSearchable.getImeOptions();
             mSearchAutoComplete.setImeOptions(mSearchAutoCompleteImeOptions);
+            
+            // If the search dialog is going to show a voice search button, then don't let
+            // the soft keyboard display a microphone button if it would have otherwise.
+            if (mSearchable.getVoiceSearchEnabled()) {
+                mSearchAutoComplete.setPrivateImeOptions(IME_OPTION_NO_MICROPHONE);
+            } else {
+                mSearchAutoComplete.setPrivateImeOptions(null);
+            }
         }
     }
     
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ff48583..3fc676b 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -597,14 +597,6 @@
     /**
      * Picks RFCOMM channels until none are left.
      * Avoids reserved channels.
-     * Ideally we would pick random channels, but in the current implementation
-     * we start with the channel that is the hash of the UUID, and try every
-     * available channel from there. This means that in most cases a given
-     * uuid will use the same channel. This is a workaround for a Bluez SDP
-     * bug where we are not updating the cache when the channel changes for a
-     * uuid.
-     * TODO: Fix the Bluez SDP caching bug, and go back to random channel
-     * selection
      */
     private static class RfcommChannelPicker {
         private static final int[] RESERVED_RFCOMM_CHANNELS =  new int[] {
@@ -637,19 +629,12 @@
             }
             mUuid = uuid;
         }
-        /* Returns next channel, or -1 if we're out */
+        /* Returns next random channel, or -1 if we're out */
         public int nextChannel() {
-            int channel = mUuid.hashCode();  // always pick the same channel to try first
-            Integer channelInt;
-            while (mChannels.size() > 0) {
-                channelInt = new Integer(channel);
-                if (mChannels.remove(channelInt)) {
-                    return channel;
-                }
-                channel = (channel % BluetoothSocket.MAX_RFCOMM_CHANNEL) + 1;
+            if (mChannels.size() == 0) {
+                return -1;
             }
-
-            return -1;
+            return mChannels.remove(sRandom.nextInt(mChannels.size()));
         }
     }
 
diff --git a/core/java/android/os/PerformanceCollector.java b/core/java/android/os/PerformanceCollector.java
index 4ca1f32..be1cf6d 100644
--- a/core/java/android/os/PerformanceCollector.java
+++ b/core/java/android/os/PerformanceCollector.java
@@ -107,6 +107,36 @@
          * @see PerformanceCollector#stopTiming(String)
          */
         public void writeStopTiming(Bundle results);
+
+        /**
+         * Callback invoked as last action in
+         * {@link PerformanceCollector#addMeasurement(String, long)} for
+         * reporting an integer type measurement.
+         *
+         * @param label short description of the metric that was measured
+         * @param value long value of the measurement
+         */
+        public void writeMeasurement(String label, long value);
+
+        /**
+         * Callback invoked as last action in
+         * {@link PerformanceCollector#addMeasurement(String, float)} for
+         * reporting a float type measurement.
+         *
+         * @param label short description of the metric that was measured
+         * @param value float value of the measurement
+         */
+        public void writeMeasurement(String label, float value);
+
+        /**
+         * Callback invoked as last action in
+         * {@link PerformanceCollector#addMeasurement(String, String)} for
+         * reporting a string field.
+         *
+         * @param label short description of the metric that was measured
+         * @param value string summary of the measurement
+         */
+        public void writeMeasurement(String label, String value);
     }
 
     /**
@@ -385,6 +415,39 @@
         return mPerfMeasurement;
     }
 
+    /**
+     * Add an integer type measurement to the collector.
+     *
+     * @param label short description of the metric that was measured
+     * @param value long value of the measurement
+     */
+    public void addMeasurement(String label, long value) {
+        if (mPerfWriter != null)
+            mPerfWriter.writeMeasurement(label, value);
+    }
+
+    /**
+     * Add a float type measurement to the collector.
+     *
+     * @param label short description of the metric that was measured
+     * @param value float value of the measurement
+     */
+    public void addMeasurement(String label, float value) {
+        if (mPerfWriter != null)
+            mPerfWriter.writeMeasurement(label, value);
+    }
+
+    /**
+     * Add a string field to the collector.
+     *
+     * @param label short description of the metric that was measured
+     * @param value string summary of the measurement
+     */
+    public void addMeasurement(String label, String value) {
+        if (mPerfWriter != null)
+            mPerfWriter.writeMeasurement(label, value);
+    }
+
     /*
      * Starts tracking memory usage, binder transactions, and real & cpu timing.
      */
diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp
index 0f8dff1..455449e 100644
--- a/core/jni/android/graphics/MaskFilter.cpp
+++ b/core/jni/android/graphics/MaskFilter.cpp
@@ -1,6 +1,7 @@
 #include "GraphicsJNI.h"
 #include "SkMaskFilter.h"
 #include "SkBlurMaskFilter.h"
+#include "SkTableMaskFilter.h"
 
 #include <jni.h>
 
@@ -39,6 +40,19 @@
         ThrowIAE_IfNull(env, filter);
         return filter;
     }
+
+    static SkMaskFilter* createTable(JNIEnv* env, jobject, jbyteArray jtable) {
+        AutoJavaByteArray autoTable(env, jtable, 256);
+        return new SkTableMaskFilter((const uint8_t*)autoTable.ptr());
+    }
+
+    static SkMaskFilter* createClipTable(JNIEnv* env, jobject, int min, int max) {
+        return SkTableMaskFilter::CreateClip(min, max);
+    }
+
+    static SkMaskFilter* createGammaTable(JNIEnv* env, jobject, float gamma) {
+        return SkTableMaskFilter::CreateGamma(gamma);
+    }
 };
 
 static JNINativeMethod gMaskFilterMethods[] = {
@@ -53,6 +67,12 @@
     { "nativeConstructor",  "([FFFF)I", (void*)SkMaskFilterGlue::createEmboss    }
 };
 
+static JNINativeMethod gTableMaskFilterMethods[] = {
+    { "nativeNewTable", "([B)I", (void*)SkMaskFilterGlue::createTable    },
+    { "nativeNewClip",  "(II)I", (void*)SkMaskFilterGlue::createClipTable    },
+    { "nativeNewGamma", "(F)I", (void*)SkMaskFilterGlue::createGammaTable    }
+};
+
 #include <android_runtime/AndroidRuntime.h>
 
 #define REG(env, name, array)                                                                       \
@@ -67,6 +87,7 @@
     REG(env, "android/graphics/MaskFilter", gMaskFilterMethods);
     REG(env, "android/graphics/BlurMaskFilter", gBlurMaskFilterMethods);
     REG(env, "android/graphics/EmbossMaskFilter", gEmbossMaskFilterMethods);
+    REG(env, "android/graphics/TableMaskFilter", gTableMaskFilterMethods);
     
     return 0;
 }
diff --git a/graphics/java/android/graphics/TableMaskFilter.java b/graphics/java/android/graphics/TableMaskFilter.java
new file mode 100644
index 0000000..a8a7ff0
--- /dev/null
+++ b/graphics/java/android/graphics/TableMaskFilter.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+/**
+ * @hide
+ */
+public class TableMaskFilter extends MaskFilter {
+
+    public TableMaskFilter(byte[] table) {
+        if (table.length < 256) {
+            throw new RuntimeException("table.length must be >= 256");
+        }
+        native_instance = nativeNewTable(table);
+    }
+    
+    private TableMaskFilter(int ni) {
+        native_instance = ni;
+    }
+    
+    public static TableMaskFilter CreateClipTable(int min, int max) {
+        return new TableMaskFilter(nativeNewClip(min, max));
+    }
+    
+    public static TableMaskFilter CreateGammaTable(float gamma) {
+        return new TableMaskFilter(nativeNewGamma(gamma));
+    }
+
+    private static native int nativeNewTable(byte[] table);
+    private static native int nativeNewClip(int min, int max);
+    private static native int nativeNewGamma(float gamma);
+}
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 0960c81..9c0c850 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -1162,7 +1162,7 @@
 
 bool AudioFlinger::MixerThread::threadLoop()
 {
-    uint32_t sleepTime = 0;
+    uint32_t sleepTime = 1000;
     uint32_t maxBufferRecoveryInUsecs = getMaxBufferRecoveryInUsecs();
     int16_t* curBuf = mMixBuffer;
     Vector< sp<Track> > tracksToRemove;
@@ -1224,6 +1224,7 @@
                     }
 
                     standbyTime = systemTime() + kStandbyTimeInNsecs;
+                    sleepTime = 1000;
                     continue;
                 }
             }
@@ -1591,7 +1592,7 @@
 
 bool AudioFlinger::DirectOutputThread::threadLoop()
 {
-    uint32_t sleepTime = 0;
+    uint32_t sleepTime = 1000;
     uint32_t maxBufferRecoveryInUsecs = getMaxBufferRecoveryInUsecs();
     sp<Track> trackToRemove;
     sp<Track> activeTrack;
@@ -1643,6 +1644,7 @@
                     }
 
                     standbyTime = systemTime() + kStandbyTimeInNsecs;
+                    sleepTime = 1000;
                     continue;
                 }
             }
@@ -1879,7 +1881,7 @@
 
 bool AudioFlinger::DuplicatingThread::threadLoop()
 {
-    uint32_t sleepTime = 0;
+    uint32_t sleepTime = 1000;
     uint32_t maxBufferRecoveryInUsecs = getMaxBufferRecoveryInUsecs();
     int16_t* curBuf = mMixBuffer;
     Vector< sp<Track> > tracksToRemove;
@@ -1940,6 +1942,7 @@
                     }
 
                     standbyTime = systemTime() + kStandbyTimeInNsecs;
+                    sleepTime = 1000;
                     continue;
                 }
             }
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index 744f2e9..5fd7904 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -40,9 +40,10 @@
 
 LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
         const sp<Client>& client, int32_t i)
-: LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
-mRefreshCache(true), mCacheAge(0), mTextureName(-1U), 
-mWidthScale(1.0f), mHeightScale(1.0f)
+    : LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
+          mRefreshCache(true), mCacheAge(0), mTextureName(-1U),
+          mWidthScale(1.0f), mHeightScale(1.0f),
+          mBlurFormat(GGL_PIXEL_FORMAT_RGB_565)
 {
 }
 
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 6590503..82a8e51 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -33,14 +33,13 @@
 #include "SurfaceFlinger.h"
 #include "DisplayHardware/DisplayHardware.h"
 
-#include "gralloc_priv.h"   // needed for msm / copybit
-
 namespace android {
 
 // ---------------------------------------------------------------------------
 
 const uint32_t LayerBuffer::typeInfo = LayerBaseClient::typeInfo | 0x20;
 const char* const LayerBuffer::typeID = "LayerBuffer";
+gralloc_module_t const* LayerBuffer::sGrallocModule = 0;
 
 // ---------------------------------------------------------------------------
 
@@ -60,6 +59,16 @@
     LayerBaseClient::onFirstRef();
     mSurface = new SurfaceLayerBuffer(mFlinger, clientIndex(),
             const_cast<LayerBuffer *>(this));
+
+    hw_module_t const* module = (hw_module_t const*)sGrallocModule;
+    if (!module) {
+        // NOTE: technically there is a race here, but it shouldn't
+        // cause any problem since hw_get_module() always returns
+        // the same value.
+        if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
+            sGrallocModule = (gralloc_module_t const *)module;
+        }
+    }
 }
 
 sp<LayerBaseClient::Surface> LayerBuffer::createSurface() const
@@ -243,30 +252,36 @@
     : mBufferHeap(buffers)
 {
     NativeBuffer& src(mNativeBuffer);
-    
-    src.crop.l = 0;
-    src.crop.t = 0;
-    src.crop.r = buffers.w;
-    src.crop.b = buffers.h;
-    
-    src.img.w       = buffers.hor_stride ?: buffers.w;
-    src.img.h       = buffers.ver_stride ?: buffers.h;
-    src.img.format  = buffers.format;
-    src.img.base    = (void*)(intptr_t(buffers.heap->base()) + offset);
+    src.img.handle = 0;
 
-    // FIXME: gross hack, we should never access private_handle_t from here,
-    // but this is needed by msm drivers
-    private_handle_t* hnd = new private_handle_t(
-            buffers.heap->heapID(), buffers.heap->getSize(), 0);
-    hnd->offset = offset;
-    src.img.handle = hnd;
+    gralloc_module_t const * module = LayerBuffer::getGrallocModule();
+    if (module && module->perform) {
+        int err = module->perform(module,
+                GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER,
+                buffers.heap->heapID(), buffers.heap->getSize(),
+                offset, buffers.heap->base(),
+                &src.img.handle);
+
+        if (err == NO_ERROR) {
+            src.crop.l = 0;
+            src.crop.t = 0;
+            src.crop.r = buffers.w;
+            src.crop.b = buffers.h;
+
+            src.img.w       = buffers.hor_stride ?: buffers.w;
+            src.img.h       = buffers.ver_stride ?: buffers.h;
+            src.img.format  = buffers.format;
+            src.img.base    = (void*)(intptr_t(buffers.heap->base()) + offset);
+        }
+    }
 }
 
 LayerBuffer::Buffer::~Buffer()
 {
     NativeBuffer& src(mNativeBuffer);
-    if (src.img.handle)
-        delete (private_handle_t*)src.img.handle;
+    if (src.img.handle) {
+        native_handle_delete(src.img.handle);
+    }
 }
 
 // ============================================================================
@@ -437,9 +452,7 @@
     }
 
     if (err != NO_ERROR) {
-        // OpenGL fall-back
-        GLuint w = 0;
-        GLuint h = 0;
+        // slower fallback
         GGLSurface t;
         t.version = sizeof(GGLSurface);
         t.width  = src.crop.r;
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 438b711..47482f4 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -91,6 +91,11 @@
         copybit_rect_t    crop;
     };
 
+    static gralloc_module_t const* sGrallocModule;
+    static gralloc_module_t const* getGrallocModule() {
+        return sGrallocModule;
+    }
+
     class Buffer : public LightRefBase<Buffer> {
     public:
         Buffer(const ISurface::BufferHeap& buffers, ssize_t offset);
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index 6698e00..f9bfe6c 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -246,8 +246,10 @@
     virtual status_t    readyToRun();
     virtual void        onFirstRef();
 
+public:     // hack to work around gcc 4.0.3 bug
     const GraphicPlane&     graphicPlane(int dpy) const;
           GraphicPlane&     graphicPlane(int dpy);
+private:
 
             void        waitForEvent();
 public:     // hack to work around gcc 4.0.3 bug
diff --git a/opengl/libagl/copybit.cpp b/opengl/libagl/copybit.cpp
index 4b9e59b..3de5b2b 100644
--- a/opengl/libagl/copybit.cpp
+++ b/opengl/libagl/copybit.cpp
@@ -74,6 +74,7 @@
     static int iterate_done(copybit_region_t const *, copybit_rect_t*) {
         return 0;
     }
+public:
     copybit_rect_t r;
 };
 
@@ -421,6 +422,20 @@
                 (enables & GGL_ENABLE_DITHER) ?
                         COPYBIT_ENABLE : COPYBIT_DISABLE);
         clipRectRegion it(c);
+
+        LOGD_IF(0,
+             "dst={%d, %d, %d, %p, %p}, "
+             "src={%d, %d, %d, %p, %p}, "
+             "drect={%d,%d,%d,%d}, "
+             "srect={%d,%d,%d,%d}, "
+             "it={%d,%d,%d,%d}, " ,
+             dst.w, dst.h, dst.format, dst.base, dst.handle,
+             src.w, src.h, src.format, src.base, src.handle,
+             drect.l, drect.t, drect.r, drect.b,
+             srect.l, srect.t, srect.r, srect.b,
+             it.r.l, it.r.t, it.r.r, it.r.b
+        );
+
         err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
     }
     if (err != NO_ERROR) {
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 3efb678..c22c21b 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -1641,8 +1641,13 @@
         if (dp == 0) {
             return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
         }
-        // since we don't have a way to know which implementation to call,
-        // we're calling all of them
+
+        /* Since we don't have a way to know which implementation to call,
+         * we're calling all of them. If at least one of the implementation
+         * succeeded, this is a success.
+         */
+
+        EGLint currentError = eglGetError();
 
         EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
         bool success = false;
@@ -1659,9 +1664,24 @@
                 }
             }
         }
-        if (!success)
+
+        if (!success) {
+            // failure, if there was an error when we entered this function,
+            // the error flag must not be updated.
+            // Otherwise, the error is whatever happened in the implementation
+            // that faulted.
+            if (currentError != EGL_SUCCESS) {
+                setError(currentError, EGL_NO_IMAGE_KHR);
+            }
             return EGL_NO_IMAGE_KHR;
-        
+        } else {
+            // In case of success, we need to clear all error flags
+            // (especially those caused by the implementation that didn't
+            // succeed). TODO: we could avoid this if we knew this was
+            // a "full" success (all implementation succeeded).
+            eglGetError();
+        }
+
         egl_image_t* result = new egl_image_t(dpy, ctx);
         memcpy(result->images, implImages, sizeof(implImages));
         return (EGLImageKHR)result;
diff --git a/opengl/tests/linetex/linetex.cpp b/opengl/tests/linetex/linetex.cpp
index 992a10c..6842940 100644
--- a/opengl/tests/linetex/linetex.cpp
+++ b/opengl/tests/linetex/linetex.cpp
@@ -68,7 +68,7 @@
      
      glBindTexture(GL_TEXTURE_2D, 0);
      glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
      glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
      glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
@@ -77,7 +77,9 @@
      glEnable(GL_TEXTURE_2D);
      glColor4f(1,1,1,1);
 
-     const uint16_t t16[64] = { 0xFFFF, 0xF800, 0x07E0, 0x001F };
+
+     // default pack-alignment is 4
+     const uint16_t t16[64] = { 0xFFFF, 0, 0xF800, 0, 0x07E0, 0, 0x001F, 0 };
 
      const GLfloat vertices[4][2] = {
              { w/2,  0 },
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 4bf606d..f68bcbb 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -211,13 +211,19 @@
     private long mScreenOnStartTime;
     private boolean mPreventScreenOn;
     private int mScreenBrightnessOverride = -1;
-    private boolean mHasHardwareAutoBrightness;
+    private boolean mUseSoftwareAutoBrightness;
     private boolean mAutoBrightessEnabled;
     private int[] mAutoBrightnessLevels;
     private int[] mLcdBacklightValues;
     private int[] mButtonBacklightValues;
     private int[] mKeyboardBacklightValues;
 
+    /*
+     * WARNING - DO NOT USE THE HARDWARE AUTO-BRIGHTNESS FEATURE
+     * Hardware auto brightness support is deprecated and will be removed in the next release.
+     */
+    private boolean mUseHardwareAutoBrightness;
+
     // Used when logging number and duration of touch-down cycles
     private long mTotalTouchDownTime;
     private long mLastTouchDown;
@@ -438,9 +444,22 @@
         mScreenOffIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
 
         Resources resources = mContext.getResources();
-        mHasHardwareAutoBrightness = resources.getBoolean(
+
+        // read settings for auto-brightness
+        mUseSoftwareAutoBrightness = resources.getBoolean(
+                com.android.internal.R.bool.config_automatic_brightness_available);
+
+        /*
+         * WARNING - DO NOT USE THE HARDWARE AUTO-BRIGHTNESS FEATURE
+         * Hardware auto brightness support is deprecated and will be removed in the next release.
+         */
+        mUseHardwareAutoBrightness = resources.getBoolean(
                 com.android.internal.R.bool.config_hardware_automatic_brightness_available);
-        if (!mHasHardwareAutoBrightness) {
+        if (mUseHardwareAutoBrightness) {
+            mUseSoftwareAutoBrightness = false;
+        }
+
+        if (mUseSoftwareAutoBrightness) {
             mAutoBrightnessLevels = resources.getIntArray(
                     com.android.internal.R.array.config_autoBrightnessLevels);
             mLcdBacklightValues = resources.getIntArray(
@@ -479,7 +498,7 @@
         // And explicitly do the initial update of our cached settings
         updateGservicesValues();
 
-        if (mAutoBrightessEnabled && !mHasHardwareAutoBrightness) {
+        if (mUseSoftwareAutoBrightness) {
             // turn the screen on
             setPowerState(SCREEN_BRIGHT);
         } else {
@@ -581,7 +600,7 @@
             switch (wl.flags & LOCK_MASK)
             {
                 case PowerManager.FULL_WAKE_LOCK:
-                    if (mAutoBrightessEnabled && !mHasHardwareAutoBrightness) {
+                    if (mUseSoftwareAutoBrightness) {
                         wl.minState = SCREEN_BRIGHT;
                     } else {
                         wl.minState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);
@@ -887,7 +906,8 @@
         pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
         pw.println("  mLightSensorValue=" + mLightSensorValue);
         pw.println("  mLightSensorPendingValue=" + mLightSensorPendingValue);
-        pw.println("  mHasHardwareAutoBrightness=" + mHasHardwareAutoBrightness);
+        pw.println("  mUseHardwareAutoBrightness=" + mUseHardwareAutoBrightness);
+        pw.println("  mUseSoftwareAutoBrightness=" + mUseSoftwareAutoBrightness);
         pw.println("  mAutoBrightessEnabled=" + mAutoBrightessEnabled);
         mScreenBrightness.dump(pw, "  mScreenBrightness: ");
         mKeyboardBrightness.dump(pw, "  mKeyboardBrightness: ");
@@ -1290,8 +1310,8 @@
 
     private int setScreenStateLocked(boolean on) {
         int err = Power.setScreenState(on);
-        if (err == 0 && !mHasHardwareAutoBrightness) {
-            enableLightSensor(on && mAutoBrightessEnabled);
+        if (err == 0 && mUseSoftwareAutoBrightness) {
+            enableLightSensor(on);
             if (!on) {
                 // make sure button and key backlights are off too
                 mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, 0);
@@ -1337,7 +1357,7 @@
                 return;
             }
 
-            if (!mDoneBooting && !(mAutoBrightessEnabled && !mHasHardwareAutoBrightness)) {
+            if (!mDoneBooting && !mUseSoftwareAutoBrightness) {
                 newState |= ALL_BRIGHT;
             }
 
@@ -1758,7 +1778,7 @@
         try {
             if (mScreenBrightnessOverride >= 0) {
                 return mScreenBrightnessOverride;
-            } else if (mLightSensorBrightness >= 0 && !mHasHardwareAutoBrightness) {
+            } else if (mLightSensorBrightness >= 0 && mUseSoftwareAutoBrightness) {
                 return mLightSensorBrightness;
             }
             final int brightness = Settings.System.getInt(mContext.getContentResolver(),
@@ -1849,8 +1869,7 @@
                 if ((mUserActivityAllowed && !mProximitySensorActive) || force) {
                     // Only turn on button backlights if a button was pressed
                     // and auto brightness is disabled
-                    if (eventType == BUTTON_EVENT &&
-                            !(mAutoBrightessEnabled && !mHasHardwareAutoBrightness)) {
+                    if (eventType == BUTTON_EVENT && !mUseSoftwareAutoBrightness) {
                         mUserState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);
                     } else {
                         // don't clear button/keyboard backlights when the screen is touched.
@@ -1908,14 +1927,17 @@
             Log.d(TAG, "lightSensorChangedLocked " + value);
         }
 
-        if (mHasHardwareAutoBrightness) return;
-
         if (mLightSensorValue != value) {
             mLightSensorValue = value;
             if ((mPowerState & BATTERY_LOW_BIT) == 0) {
                 int lcdValue = getAutoBrightnessValue(value, mLcdBacklightValues);
                 int buttonValue = getAutoBrightnessValue(value, mButtonBacklightValues);
-                int keyboardValue = getAutoBrightnessValue(value, mKeyboardBacklightValues);
+                int keyboardValue;
+                if (mKeyboardVisible) {
+                    keyboardValue = getAutoBrightnessValue(value, mKeyboardBacklightValues);
+                } else {
+                    keyboardValue = 0;
+                }
                 mLightSensorBrightness = lcdValue;
 
                 if (mDebugLightSensor) {
@@ -1925,7 +1947,7 @@
                 }
 
                 boolean startAnimation = false;
-                if (mScreenBrightnessOverride < 0) {
+                if (mAutoBrightessEnabled && mScreenBrightnessOverride < 0) {
                     if (ANIMATE_SCREEN_LIGHTS) {
                         if (mScreenBrightness.setTargetLocked(lcdValue,
                                 AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_SCREEN_BRIGHTNESS,
@@ -2037,6 +2059,14 @@
                 // will take care of turning on due to a true change to the lid
                 // switch and synchronized with the lock screen.
                 if ((mPowerState & SCREEN_ON_BIT) != 0) {
+                    if (mUseSoftwareAutoBrightness) {
+                        // force recompute of backlight values
+                        if (mLightSensorValue >= 0) {
+                            int value = (int)mLightSensorValue;
+                            mLightSensorValue = -1;
+                            lightSensorChangedLocked(value);
+                        }
+                    }
                     userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true);
                 }
             }
@@ -2049,7 +2079,6 @@
     public void enableUserActivity(boolean enabled) {
         synchronized (mLocks) {
             mUserActivityAllowed = enabled;
-            mLastEventTime = SystemClock.uptimeMillis(); // we might need to pass this in
         }
     }
 
@@ -2057,18 +2086,20 @@
         boolean enabled = (mode == SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
         if (mAutoBrightessEnabled != enabled) {
             mAutoBrightessEnabled = enabled;
-            // reset computed brightness
-            mLightSensorValue = -1;
-            mLightSensorBrightness = -1;
 
-            if (mHasHardwareAutoBrightness) {
+            if (mUseHardwareAutoBrightness) {
                 // When setting auto-brightness, must reset the brightness afterwards
                 mHardware.setAutoBrightness_UNCHECKED(enabled);
                 if (screenIsOn()) {
                     setBacklightBrightness((int)mScreenBrightness.curValue);
                 }
-            } else {
-                enableLightSensor(screenIsOn() && enabled);
+            } else if (mUseSoftwareAutoBrightness && screenIsOn()) {
+                // force recompute of backlight values
+                if (mLightSensorValue >= 0) {
+                    int value = (int)mLightSensorValue;
+                    mLightSensorValue = -1;
+                    lightSensorChangedLocked(value);
+                }
             }
         }
     }
@@ -2222,9 +2253,9 @@
         mSensorManager = new SensorManager(mHandlerThread.getLooper());
         mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
         // don't bother with the light sensor if auto brightness is handled in hardware
-        if (!mHasHardwareAutoBrightness) {
+        if (mUseSoftwareAutoBrightness) {
             mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
-            enableLightSensor(mAutoBrightessEnabled);
+            enableLightSensor(true);
         }
 
         synchronized (mLocks) {
@@ -2266,7 +2297,8 @@
         // Don't let applications turn the screen all the way off
         brightness = Math.max(brightness, Power.BRIGHTNESS_DIM);
         mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT, brightness);
-        mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD, brightness);
+        mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
+            (mKeyboardVisible ? brightness : 0));
         mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, brightness);
         long identity = Binder.clearCallingIdentity();
         try {
diff --git a/test-runner/android/test/InstrumentationTestRunner.java b/test-runner/android/test/InstrumentationTestRunner.java
index b9978d6..773d7a9 100644
--- a/test-runner/android/test/InstrumentationTestRunner.java
+++ b/test-runner/android/test/InstrumentationTestRunner.java
@@ -227,17 +227,22 @@
      */
     private static final String REPORT_KEY_COVERAGE_PATH = "coverageFilePath";
     /**
+     * If included at the start of reporting keys, this prefix marks the key as a performance
+     * metric.
+     */
+    private static final String REPORT_KEY_PREFIX = "performance.";
+    /**
      * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
      * reports the cpu time in milliseconds of the current test.
      */
     private static final String REPORT_KEY_PERF_CPU_TIME =
-        "performance." + PerformanceCollector.METRIC_KEY_CPU_TIME;
+        REPORT_KEY_PREFIX + PerformanceCollector.METRIC_KEY_CPU_TIME;
     /**
      * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
      * reports the run time in milliseconds of the current test.
      */
     private static final String REPORT_KEY_PERF_EXECUTION_TIME =
-        "performance." + PerformanceCollector.METRIC_KEY_EXECUTION_TIME;
+        REPORT_KEY_PREFIX + PerformanceCollector.METRIC_KEY_EXECUTION_TIME;
 
     /**
      * The test is starting.
@@ -739,11 +744,9 @@
         }
 
         public void writeEndSnapshot(Bundle results) {
-            // Copy all snapshot data fields as type long into mResults, which
-            // is outputted via Instrumentation.finish
-            for (String key : results.keySet()) {
-                mResults.putLong(key, results.getLong(key));
-            }
+            // Copy all snapshot data fields into mResults, which is outputted
+            // via Instrumentation.finish
+            mResults.putAll(results);
         }
 
         public void writeStartTiming(String label) {
@@ -768,6 +771,18 @@
             }
         }
 
+        public void writeMeasurement(String label, long value) {
+            mTestResult.putLong(REPORT_KEY_PREFIX + label, value);
+        }
+
+        public void writeMeasurement(String label, float value) {
+            mTestResult.putFloat(REPORT_KEY_PREFIX + label, value);
+        }
+
+        public void writeMeasurement(String label, String value) {
+            mTestResult.putString(REPORT_KEY_PREFIX + label, value);
+        }
+
         // TODO report the end of the cycle
     }
 }
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/PerformanceCollectorTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/PerformanceCollectorTest.java
index d0fdff4..25b6e0e 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/os/PerformanceCollectorTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/PerformanceCollectorTest.java
@@ -19,8 +19,9 @@
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.PerformanceCollector;
+import android.os.Process;
 import android.os.PerformanceCollector.PerformanceResultsWriter;
-import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
@@ -44,6 +45,7 @@
         mPerfCollector = null;
     }
 
+    @SmallTest
     public void testBeginSnapshotNoWriter() throws Exception {
         mPerfCollector.beginSnapshot("testBeginSnapshotNoWriter");
 
@@ -54,15 +56,16 @@
         assertEquals(2, snapshot.size());
     }
 
-    @LargeTest
+    @SmallTest
     public void testEndSnapshotNoWriter() throws Exception {
         mPerfCollector.beginSnapshot("testEndSnapshotNoWriter");
-        sleepForRandomLongPeriod();
+        workForRandomLongPeriod();
         Bundle snapshot = mPerfCollector.endSnapshot();
 
         verifySnapshotBundle(snapshot);
     }
 
+    @SmallTest
     public void testStartTimingNoWriter() throws Exception {
         mPerfCollector.startTiming("testStartTimingNoWriter");
 
@@ -73,21 +76,23 @@
         verifyTimingBundle(measurement, new ArrayList<String>());
     }
 
+    @SmallTest
     public void testAddIterationNoWriter() throws Exception {
         mPerfCollector.startTiming("testAddIterationNoWriter");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         Bundle iteration = mPerfCollector.addIteration("timing1");
 
         verifyIterationBundle(iteration, "timing1");
     }
 
+    @SmallTest
     public void testStopTimingNoWriter() throws Exception {
         mPerfCollector.startTiming("testStopTimingNoWriter");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("timing2");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("timing3");
-        sleepForRandomShortPeriod();
+        workForRandomShortPeriod();
         Bundle timing = mPerfCollector.stopTiming("timing4");
 
         ArrayList<String> labels = new ArrayList<String>();
@@ -97,6 +102,7 @@
         verifyTimingBundle(timing, labels);
     }
 
+    @SmallTest
     public void testBeginSnapshot() throws Exception {
         MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
         mPerfCollector.setPerformanceResultsWriter(writer);
@@ -110,19 +116,20 @@
         assertEquals(2, snapshot.size());
     }
 
-    @LargeTest
+    @SmallTest
     public void testEndSnapshot() throws Exception {
         MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
         mPerfCollector.setPerformanceResultsWriter(writer);
         mPerfCollector.beginSnapshot("testEndSnapshot");
-        sleepForRandomLongPeriod();
+        workForRandomLongPeriod();
         Bundle snapshot1 = mPerfCollector.endSnapshot();
         Bundle snapshot2 = writer.snapshotResults;
 
-        assertTrue(snapshot1.equals(snapshot2));
+        assertEqualsBundle(snapshot1, snapshot2);
         verifySnapshotBundle(snapshot1);
     }
 
+    @SmallTest
     public void testStartTiming() throws Exception {
         MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
         mPerfCollector.setPerformanceResultsWriter(writer);
@@ -136,21 +143,23 @@
         verifyTimingBundle(measurement, new ArrayList<String>());
     }
 
+    @SmallTest
     public void testAddIteration() throws Exception {
         mPerfCollector.startTiming("testAddIteration");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         Bundle iteration = mPerfCollector.addIteration("timing5");
 
         verifyIterationBundle(iteration, "timing5");
     }
 
+    @SmallTest
     public void testStopTiming() throws Exception {
         mPerfCollector.startTiming("testStopTiming");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("timing6");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("timing7");
-        sleepForRandomShortPeriod();
+        workForRandomShortPeriod();
         Bundle timing = mPerfCollector.stopTiming("timing8");
 
         ArrayList<String> labels = new ArrayList<String>();
@@ -160,28 +169,90 @@
         verifyTimingBundle(timing, labels);
     }
 
-    // TODO: flaky test
-    // @LargeTest
+    @SmallTest
+    public void testAddMeasurementLong() throws Exception {
+        MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
+        mPerfCollector.setPerformanceResultsWriter(writer);
+        mPerfCollector.startTiming("testAddMeasurementLong");
+        mPerfCollector.addMeasurement("testAddMeasurementLongZero", 0);
+        mPerfCollector.addMeasurement("testAddMeasurementLongPos", 348573);
+        mPerfCollector.addMeasurement("testAddMeasurementLongNeg", -19354);
+        mPerfCollector.stopTiming("");
+
+        assertEquals("testAddMeasurementLong", writer.timingLabel);
+        Bundle results = writer.timingResults;
+        assertEquals(4, results.size());
+        assertTrue(results.containsKey("testAddMeasurementLongZero"));
+        assertEquals(0, results.getLong("testAddMeasurementLongZero"));
+        assertTrue(results.containsKey("testAddMeasurementLongPos"));
+        assertEquals(348573, results.getLong("testAddMeasurementLongPos"));
+        assertTrue(results.containsKey("testAddMeasurementLongNeg"));
+        assertEquals(-19354, results.getLong("testAddMeasurementLongNeg"));
+    }
+
+    @SmallTest
+    public void testAddMeasurementFloat() throws Exception {
+        MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
+        mPerfCollector.setPerformanceResultsWriter(writer);
+        mPerfCollector.startTiming("testAddMeasurementFloat");
+        mPerfCollector.addMeasurement("testAddMeasurementFloatZero", 0.0f);
+        mPerfCollector.addMeasurement("testAddMeasurementFloatPos", 348573.345f);
+        mPerfCollector.addMeasurement("testAddMeasurementFloatNeg", -19354.093f);
+        mPerfCollector.stopTiming("");
+
+        assertEquals("testAddMeasurementFloat", writer.timingLabel);
+        Bundle results = writer.timingResults;
+        assertEquals(4, results.size());
+        assertTrue(results.containsKey("testAddMeasurementFloatZero"));
+        assertEquals(0.0f, results.getFloat("testAddMeasurementFloatZero"));
+        assertTrue(results.containsKey("testAddMeasurementFloatPos"));
+        assertEquals(348573.345f, results.getFloat("testAddMeasurementFloatPos"));
+        assertTrue(results.containsKey("testAddMeasurementFloatNeg"));
+        assertEquals(-19354.093f, results.getFloat("testAddMeasurementFloatNeg"));
+    }
+
+    @SmallTest
+    public void testAddMeasurementString() throws Exception {
+        MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
+        mPerfCollector.setPerformanceResultsWriter(writer);
+        mPerfCollector.startTiming("testAddMeasurementString");
+        mPerfCollector.addMeasurement("testAddMeasurementStringNull", null);
+        mPerfCollector.addMeasurement("testAddMeasurementStringEmpty", "");
+        mPerfCollector.addMeasurement("testAddMeasurementStringNonEmpty", "Hello World");
+        mPerfCollector.stopTiming("");
+
+        assertEquals("testAddMeasurementString", writer.timingLabel);
+        Bundle results = writer.timingResults;
+        assertEquals(4, results.size());
+        assertTrue(results.containsKey("testAddMeasurementStringNull"));
+        assertNull(results.getString("testAddMeasurementStringNull"));
+        assertTrue(results.containsKey("testAddMeasurementStringEmpty"));
+        assertEquals("", results.getString("testAddMeasurementStringEmpty"));
+        assertTrue(results.containsKey("testAddMeasurementStringNonEmpty"));
+        assertEquals("Hello World", results.getString("testAddMeasurementStringNonEmpty"));
+    }
+
+    @SmallTest
     public void testSimpleSequence() throws Exception {
         MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
         mPerfCollector.setPerformanceResultsWriter(writer);
         mPerfCollector.beginSnapshot("testSimpleSequence");
         mPerfCollector.startTiming("testSimpleSequenceTiming");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("iteration1");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("iteration2");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("iteration3");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("iteration4");
-        sleepForRandomShortPeriod();
+        workForRandomShortPeriod();
         Bundle timing = mPerfCollector.stopTiming("iteration5");
-        sleepForRandomLongPeriod();
+        workForRandomLongPeriod();
         Bundle snapshot1 = mPerfCollector.endSnapshot();
         Bundle snapshot2 = writer.snapshotResults;
 
-        assertTrue(snapshot1.equals(snapshot2));
+        assertEqualsBundle(snapshot1, snapshot2);
         verifySnapshotBundle(snapshot1);
 
         ArrayList<String> labels = new ArrayList<String>();
@@ -193,60 +264,59 @@
         verifyTimingBundle(timing, labels);
     }
 
-    // TODO: flaky test
-    // @LargeTest
+    @SmallTest
     public void testLongSequence() throws Exception {
         MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
         mPerfCollector.setPerformanceResultsWriter(writer);
         mPerfCollector.beginSnapshot("testLongSequence");
         mPerfCollector.startTiming("testLongSequenceTiming1");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("iteration1");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("iteration2");
-        sleepForRandomShortPeriod();
+        workForRandomShortPeriod();
         Bundle timing1 = mPerfCollector.stopTiming("iteration3");
-        sleepForRandomLongPeriod();
+        workForRandomLongPeriod();
 
         mPerfCollector.startTiming("testLongSequenceTiming2");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("iteration4");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("iteration5");
-        sleepForRandomShortPeriod();
+        workForRandomShortPeriod();
         Bundle timing2 = mPerfCollector.stopTiming("iteration6");
-        sleepForRandomLongPeriod();
+        workForRandomLongPeriod();
 
         mPerfCollector.startTiming("testLongSequenceTiming3");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("iteration7");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("iteration8");
-        sleepForRandomShortPeriod();
+        workForRandomShortPeriod();
         Bundle timing3 = mPerfCollector.stopTiming("iteration9");
-        sleepForRandomLongPeriod();
+        workForRandomLongPeriod();
 
         mPerfCollector.startTiming("testLongSequenceTiming4");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("iteration10");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("iteration11");
-        sleepForRandomShortPeriod();
+        workForRandomShortPeriod();
         Bundle timing4 = mPerfCollector.stopTiming("iteration12");
-        sleepForRandomLongPeriod();
+        workForRandomLongPeriod();
 
         mPerfCollector.startTiming("testLongSequenceTiming5");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("iteration13");
-        sleepForRandomTinyPeriod();
+        workForRandomTinyPeriod();
         mPerfCollector.addIteration("iteration14");
-        sleepForRandomShortPeriod();
+        workForRandomShortPeriod();
         Bundle timing5 = mPerfCollector.stopTiming("iteration15");
-        sleepForRandomLongPeriod();
+        workForRandomLongPeriod();
         Bundle snapshot1 = mPerfCollector.endSnapshot();
         Bundle snapshot2 = writer.snapshotResults;
 
-        assertTrue(snapshot1.equals(snapshot2));
+        assertEqualsBundle(snapshot1, snapshot2);
         verifySnapshotBundle(snapshot1);
 
         ArrayList<String> labels1 = new ArrayList<String>();
@@ -280,57 +350,53 @@
      * Verify that snapshotting and timing do not interfere w/ each other,
      * by staggering calls to snapshot and timing functions.
      */
-    @LargeTest
+    @SmallTest
     public void testOutOfOrderSequence() {
         MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
         mPerfCollector.setPerformanceResultsWriter(writer);
         mPerfCollector.startTiming("testOutOfOrderSequenceTiming");
-        sleepForRandomShortPeriod();
+        workForRandomShortPeriod();
         mPerfCollector.beginSnapshot("testOutOfOrderSequenceSnapshot");
-        sleepForRandomShortPeriod();
+        workForRandomShortPeriod();
         Bundle timing1 = mPerfCollector.stopTiming("timing1");
-        sleepForRandomShortPeriod();
+        workForRandomShortPeriod();
         Bundle snapshot1 = mPerfCollector.endSnapshot();
 
         Bundle timing2 = writer.timingResults;
         Bundle snapshot2 = writer.snapshotResults;
 
-        assertTrue(snapshot1.equals(snapshot2));
+        assertEqualsBundle(snapshot1, snapshot2);
         verifySnapshotBundle(snapshot1);
 
-        assertTrue(timing1.equals(timing2));
+        assertEqualsBundle(timing1, timing2);
         ArrayList<String> labels = new ArrayList<String>();
         labels.add("timing1");
         verifyTimingBundle(timing1, labels);
     }
 
-    private void sleepForRandomPeriod(int minDuration, int maxDuration) {
+    private void workForRandomPeriod(int minDuration, int maxDuration) {
         Random random = new Random();
         int period = minDuration + random.nextInt(maxDuration - minDuration);
-        int slept = 0;
-        // Generate random positive amount of work, so cpu time is measurable in
+        long start = Process.getElapsedCpuTime();
+        // Generate positive amount of work, so cpu time is measurable in
         // milliseconds
-        while (slept < period) {
-            int step = random.nextInt(minDuration/5);
-            try {
-                Thread.sleep(step);
-            } catch (InterruptedException e ) {
-                // eat the exception
+        while (Process.getElapsedCpuTime() - start < period) {
+            for (int i = 0, temp = 0; i < 50; i++ ) {
+                temp += i;
             }
-            slept += step;
         }
     }
 
-    private void sleepForRandomTinyPeriod() {
-        sleepForRandomPeriod(25, 50);
+    private void workForRandomTinyPeriod() {
+        workForRandomPeriod(2, 5);
     }
 
-    private void sleepForRandomShortPeriod() {
-        sleepForRandomPeriod(100, 250);
+    private void workForRandomShortPeriod() {
+        workForRandomPeriod(10, 25);
     }
 
-    private void sleepForRandomLongPeriod() {
-        sleepForRandomPeriod(500, 1000);
+    private void workForRandomLongPeriod() {
+        workForRandomPeriod(50, 100);
     }
 
     private void verifySnapshotBundle(Bundle snapshot) {
@@ -411,6 +477,13 @@
         }
     }
 
+    private void assertEqualsBundle(Bundle b1, Bundle b2) {
+        assertEquals(b1.keySet(), b2.keySet());
+        for (String key : b1.keySet()) {
+            assertEquals(b1.get(key), b2.get(key));
+        }
+    }
+
     private Object readPrivateField(String fieldName, Object object) throws Exception {
         Field f = object.getClass().getDeclaredField(fieldName);
         f.setAccessible(true);
@@ -429,7 +502,7 @@
         }
 
         public void writeEndSnapshot(Bundle results) {
-            snapshotResults = results;
+            snapshotResults.putAll(results);
         }
 
         public void writeStartTiming(String label) {
@@ -437,7 +510,19 @@
         }
 
         public void writeStopTiming(Bundle results) {
-            timingResults = results;
+            timingResults.putAll(results);
+        }
+
+        public void writeMeasurement(String label, long value) {
+            timingResults.putLong(label, value);
+        }
+
+        public void writeMeasurement(String label, float value) {
+            timingResults.putFloat(label, value);
+        }
+
+        public void writeMeasurement(String label, String value) {
+            timingResults.putString(label, value);
         }
     }
 }