Merge "Tuning parameters for mobile RSSI." into ics-mr1
diff --git a/api/current.txt b/api/current.txt
index c94d485..e186dfb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3245,6 +3245,7 @@
     method public final boolean isInLayout();
     method public final boolean isRemoving();
     method public final boolean isResumed();
+    method public boolean isStartDeferred();
     method public final boolean isVisible();
     method public void onActivityCreated(android.os.Bundle);
     method public void onActivityResult(int, int, android.content.Intent);
@@ -3280,6 +3281,7 @@
     method public void setInitialSavedState(android.app.Fragment.SavedState);
     method public void setMenuVisibility(boolean);
     method public void setRetainInstance(boolean);
+    method public void setStartDeferred(boolean);
     method public void setTargetFragment(android.app.Fragment, int);
     method public void startActivity(android.content.Intent);
     method public void startActivityForResult(android.content.Intent, int);
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index d423d98..9b01b7f 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -339,6 +339,7 @@
     private static final HashMap<String, Class<?>> sClassMap =
             new HashMap<String, Class<?>>();
     
+    static final int INVALID_STATE = -1;   // Invalid state used as a null value.
     static final int INITIALIZING = 0;     // Not yet created.
     static final int CREATED = 1;          // Created.
     static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
@@ -403,7 +404,7 @@
     // The fragment manager we are associated with.  Set as soon as the
     // fragment is used in a transaction; cleared after it has been removed
     // from all transactions.
-    FragmentManager mFragmentManager;
+    FragmentManagerImpl mFragmentManager;
 
     // Activity this fragment is attached to.
     Activity mActivity;
@@ -453,6 +454,10 @@
     // The View generated for this fragment.
     View mView;
     
+    // Whether this fragment should defer starting until after other fragments
+    // have been started and their loaders are finished.
+    boolean mDeferStart;
+
     LoaderManagerImpl mLoaderManager;
     boolean mLoadersStarted;
     boolean mCheckedForLoaderManager;
@@ -910,6 +915,34 @@
     }
 
     /**
+     * Set whether this fragment should enter the started state as normal or if
+     * start should be deferred until a system-determined convenient time, such
+     * as after any loaders have completed their work.
+     *
+     * <p>This option is not sticky across fragment starts; after a deferred start
+     * completes this option will be set to false.</p>
+     *
+     * @param deferResume true if this fragment can defer its resume until after others
+     */
+    public void setStartDeferred(boolean deferResume) {
+        if (mDeferStart && !deferResume) {
+            mFragmentManager.performPendingDeferredStart(this);
+        }
+        mDeferStart = deferResume;
+    }
+
+    /**
+     * Returns true if this fragment's move to the started state has been deferred.
+     * If this returns true it will be started once other fragments' loaders
+     * have finished running.
+     *
+     * @return true if this fragment's start has been deferred.
+     */
+    public boolean isStartDeferred() {
+        return mDeferStart;
+    }
+
+    /**
      * Return the LoaderManager for this fragment, creating it if needed.
      */
     public LoaderManager getLoaderManager() {
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 3da4f29..58cd27c 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -709,6 +709,13 @@
         return AnimatorInflater.loadAnimator(mActivity, anim);
     }
     
+    public void performPendingDeferredStart(Fragment f) {
+        if (f.mDeferStart) {
+            f.mDeferStart = false;
+            moveToState(f, mCurState, 0, 0);
+        }
+    }
+
     void moveToState(Fragment f, int newState, int transit, int transitionStyle) {
         // Fragments that are not currently added will sit in the onCreate() state.
         if (!f.mAdded && newState > Fragment.CREATED) {
@@ -718,7 +725,10 @@
             // While removing a fragment, we can't change it to a higher state.
             newState = f.mState;
         }
-        
+        // Defer start if requested; don't allow it to move to STARTED or higher.
+        if (f.mDeferStart && newState > Fragment.STOPPED) {
+            newState = Fragment.STOPPED;
+        }
         if (f.mState < newState) {
             // For fragments that are created from a layout, when restoring from
             // state we don't want to allow them to be created until they are
@@ -992,13 +1002,21 @@
         
         mCurState = newState;
         if (mActive != null) {
+            boolean loadersRunning = false;
             for (int i=0; i<mActive.size(); i++) {
                 Fragment f = mActive.get(i);
                 if (f != null) {
                     moveToState(f, newState, transit, transitStyle);
+                    if (f.mLoaderManager != null) {
+                        loadersRunning |= f.mLoaderManager.hasRunningLoaders();
+                    }
                 }
             }
 
+            if (!loadersRunning) {
+                startPendingDeferredFragments();
+            }
+
             if (mNeedMenuInvalidate && mActivity != null && mCurState == Fragment.RESUMED) {
                 mActivity.invalidateOptionsMenu();
                 mNeedMenuInvalidate = false;
@@ -1006,6 +1024,15 @@
         }
     }
     
+    void startPendingDeferredFragments() {
+        for (int i=0; i<mActive.size(); i++) {
+            Fragment f = mActive.get(i);
+            if (f != null) {
+                performPendingDeferredStart(f);
+            }
+        }
+    }
+
     void makeActive(Fragment f) {
         if (f.mIndex >= 0) {
             return;
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index 89e9ddd..aef0c6f 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -418,6 +418,10 @@
                 info.destroy();
                 mInactiveLoaders.remove(mId);
             }
+
+            if (!hasRunningLoaders() && mActivity != null) {
+                mActivity.mFragments.startPendingDeferredFragments();
+            }
         }
 
         void callOnLoadFinished(Loader<Object> loader, Object data) {
@@ -820,4 +824,14 @@
             }
         }
     }
+
+    public boolean hasRunningLoaders() {
+        boolean loadersRunning = false;
+        final int count = mLoaders.size();
+        for (int i = 0; i < count; i++) {
+            final LoaderInfo li = mLoaders.valueAt(i);
+            loadersRunning |= li.mStarted && !li.mDeliveredData;
+        }
+        return loadersRunning;
+    }
 }
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index 9c93324..31e6f02c 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -468,7 +468,7 @@
         }
         acquireReference();
         try {
-            nativeCopyStringToBuffer(mWindowPtr, row, column, buffer);
+            nativeCopyStringToBuffer(mWindowPtr, row - mStartPos, column, buffer);
         } finally {
             releaseReference();
         }
diff --git a/core/java/android/speech/tts/FileSynthesisCallback.java b/core/java/android/speech/tts/FileSynthesisCallback.java
index 5808919..04c3377 100644
--- a/core/java/android/speech/tts/FileSynthesisCallback.java
+++ b/core/java/android/speech/tts/FileSynthesisCallback.java
@@ -16,10 +16,10 @@
 package android.speech.tts;
 
 import android.media.AudioFormat;
+import android.os.FileUtils;
 import android.util.Log;
 
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
@@ -63,7 +63,7 @@
      * Must be called while holding the monitor on {@link #mStateLock}.
      */
     private void cleanUp() {
-        closeFile();
+        closeFileAndWidenPermissions();
         if (mFile != null) {
             mFileName.delete();
         }
@@ -72,7 +72,7 @@
     /**
      * Must be called while holding the monitor on {@link #mStateLock}.
      */
-    private void closeFile() {
+    private void closeFileAndWidenPermissions() {
         try {
             if (mFile != null) {
                 mFile.close();
@@ -81,6 +81,18 @@
         } catch (IOException ex) {
             Log.e(TAG, "Failed to close " + mFileName + ": " + ex);
         }
+
+        try {
+            // Make the written file readable and writeable by everyone.
+            // This allows the app that requested synthesis to read the file.
+            //
+            // Note that the directory this file was written must have already
+            // been world writeable in order it to have been
+            // written to in the first place.
+            FileUtils.setPermissions(mFileName.getAbsolutePath(), 0666, -1, -1); //-rw-rw-rw
+        } catch (SecurityException se) {
+            Log.e(TAG, "Security exception setting rw permissions on : " + mFileName);
+        }
     }
 
     @Override
@@ -168,7 +180,7 @@
                 int dataLength = (int) (mFile.length() - WAV_HEADER_LENGTH);
                 mFile.write(
                         makeWavHeader(mSampleRateInHz, mAudioFormat, mChannelCount, dataLength));
-                closeFile();
+                closeFileAndWidenPermissions();
                 mDone = true;
                 return TextToSpeech.SUCCESS;
             } catch (IOException ex) {
diff --git a/core/java/com/android/internal/widget/DigitalClock.java b/core/java/com/android/internal/widget/DigitalClock.java
index 18a4794..6f24eba 100644
--- a/core/java/com/android/internal/widget/DigitalClock.java
+++ b/core/java/com/android/internal/widget/DigitalClock.java
@@ -168,6 +168,8 @@
         /* The time display consists of two tones. That's why we have two overlapping text views. */
         mTimeDisplayBackground = (TextView) findViewById(R.id.timeDisplayBackground);
         mTimeDisplayBackground.setTypeface(sBackgroundFont);
+        mTimeDisplayBackground.setVisibility(View.INVISIBLE);
+
         mTimeDisplayForeground = (TextView) findViewById(R.id.timeDisplayForeground);
         mTimeDisplayForeground.setTypeface(sForegroundFont);
         mAmPm = new AmPm(this, null);
diff --git a/core/res/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_normal.png b/core/res/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_normal.png
new file mode 100644
index 0000000..f28fe38
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_normal.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_pressed.png b/core/res/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_pressed.png
new file mode 100644
index 0000000..728fc67
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_normal.png b/core/res/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_normal.png
new file mode 100644
index 0000000..99e742f
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_normal.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_pressed.png b/core/res/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_pressed.png
new file mode 100644
index 0000000..c7da024
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_normal.png b/core/res/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_normal.png
new file mode 100644
index 0000000..75e4783
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_normal.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_pressed.png b/core/res/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_pressed.png
new file mode 100644
index 0000000..534c10b
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_pressed.png
Binary files differ
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
index d32cd0c..23b2fcb 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
@@ -57,11 +57,27 @@
             android:drawablePadding="4dip"
             />
 
-        <com.android.internal.widget.WaveView
+        <com.android.internal.widget.multiwaveview.MultiWaveView
             android:id="@+id/unlock_widget"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_alignParentBottom="true"
             android:layout_gravity="center"
+
+            android:targetDrawables="@array/lockscreen_targets_with_camera"
+            android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera"
+            android:directionDescriptions="@array/lockscreen_direction_descriptions"
+            android:handleDrawable="@drawable/ic_lockscreen_handle"
+            android:waveDrawable="@drawable/ic_lockscreen_outerring"
+            android:outerRadius="@dimen/multiwaveview_target_placement_radius"
+            android:snapMargin="@dimen/multiwaveview_snap_margin"
+            android:hitRadius="@dimen/multiwaveview_hit_radius"
+            android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right"
+            android:horizontalOffset="0dip"
+            android:verticalOffset="60dip"
+            android:feedbackCount="3"
+            android:vibrationDuration="20"
             />
 
         <!-- emergency call button shown when sim is PUKd and tab_selector is hidden -->
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
index dd29164..66223f2 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
@@ -61,13 +61,27 @@
             android:layout_alignParentTop="true"
             android:drawablePadding="4dip"/>
 
-        <com.android.internal.widget.WaveView
+        <com.android.internal.widget.multiwaveview.MultiWaveView
             android:id="@+id/unlock_widget"
-            android:layout_width="wrap_content"
+            android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:layout_rowSpan="7"
             android:layout_gravity="center_vertical|center_horizontal"
-            android:layout_marginRight="0dip"
-            android:layout_weight="1.0"/>
+
+            android:targetDrawables="@array/lockscreen_targets_with_camera"
+            android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera"
+            android:directionDescriptions="@array/lockscreen_direction_descriptions"
+            android:handleDrawable="@drawable/ic_lockscreen_handle"
+            android:waveDrawable="@drawable/ic_lockscreen_outerring"
+            android:outerRadius="@dimen/multiwaveview_target_placement_radius"
+            android:snapMargin="@dimen/multiwaveview_snap_margin"
+            android:hitRadius="@dimen/multiwaveview_hit_radius"
+            android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right"
+            android:feedbackCount="3"
+            android:vibrationDuration="20"
+            android:horizontalOffset="0dip"
+            android:verticalOffset="0dip"
+        />
 
         <!-- emergency call button shown when sim is PUKd and tab_selector is hidden -->
         <Button
diff --git a/core/res/res/values-mcc208-mnc10/config.xml b/core/res/res/values-mcc208-mnc10/config.xml
new file mode 100755
index 0000000..99cc599
--- /dev/null
+++ b/core/res/res/values-mcc208-mnc10/config.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
+    <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
+    <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
+    <integer-array translatable="false" name="config_tether_upstream_types">
+      <item>1</item>
+      <item>4</item>
+    </integer-array>
+
+    <!-- String containing the apn value for tethering.  May be overriden by secure settings
+         TETHER_DUN_APN.  Value is a comma separated series of strings:
+         "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
+         note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
+    <string translatable="false" name="config_tether_apndata">SFR Option Modem,websfr,,,,,,,,,208,10,,DUN"</string>
+
+</resources>
diff --git a/core/res/res/values-sw600dp-land/arrays.xml b/core/res/res/values-sw600dp-land/arrays.xml
new file mode 100644
index 0000000..6304bc0
--- /dev/null
+++ b/core/res/res/values-sw600dp-land/arrays.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Resources for MultiWaveView in LockScreen -->
+    <array name="lockscreen_targets_when_silent">
+        <item>@drawable/ic_lockscreen_unlock</item>
+        <item>@null</item>
+        <item>@drawable/ic_lockscreen_soundon</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_target_descriptions_when_silent">
+        <item>@string/description_target_unlock</item>
+        <item>@null</item>
+        <item>@string/description_target_soundon</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_direction_descriptions">
+        <item>@string/description_direction_right</item>
+        <item>@null</item>
+        <item>@string/description_direction_left</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_targets_when_soundon">
+        <item>@drawable/ic_lockscreen_unlock</item>
+        <item>@null</item>
+        <item>@drawable/ic_lockscreen_silent</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_target_descriptions_when_soundon">
+        <item>@string/description_target_unlock</item>
+        <item>@null</item>
+        <item>@string/description_target_silent</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_targets_with_camera">
+        <item>@drawable/ic_lockscreen_unlock</item>
+        <item>@null</item>
+        <item>@drawable/ic_lockscreen_camera</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_target_descriptions_with_camera">
+        <item>@string/description_target_unlock</item>
+        <item>@null</item>
+        <item>@string/description_target_camera</item>
+        <item>@null</item>
+    </array>
+
+</resources>
diff --git a/core/res/res/values-sw600dp/colors.xml b/core/res/res/values-sw600dp/colors.xml
index edd2712..f59b1f2 100644
--- a/core/res/res/values-sw600dp/colors.xml
+++ b/core/res/res/values-sw600dp/colors.xml
@@ -19,8 +19,8 @@
 -->
 <resources>
     <!-- keyguard clock -->
-    <color name="lockscreen_clock_background">#b3ffffff</color>
-    <color name="lockscreen_clock_foreground">#7affffff</color>
+    <color name="lockscreen_clock_background">#ffffffff</color>
+    <color name="lockscreen_clock_foreground">#ffffffff</color>
     <color name="lockscreen_clock_am_pm">#ffffffff</color>
     <color name="lockscreen_owner_info">#ff9a9a9a</color>
 
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index c37871b..b1a4b42 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -107,9 +107,9 @@
     <color name="keyguard_text_color_decline">#fe0a5a</color>
 
     <!-- keyguard clock -->
-    <color name="lockscreen_clock_background">#e5ffffff</color>
-    <color name="lockscreen_clock_foreground">#e5ffffff</color>
-    <color name="lockscreen_clock_am_pm">#ff9a9a9a</color>
+    <color name="lockscreen_clock_background">#ffffffff</color>
+    <color name="lockscreen_clock_foreground">#ffffffff</color>
+    <color name="lockscreen_clock_am_pm">#ffffffff</color>
     <color name="lockscreen_owner_info">#ff9a9a9a</color>
 
     <!-- FaceLock -->
diff --git a/data/fonts/Roboto-Bold.ttf b/data/fonts/Roboto-Bold.ttf
index b1546b6..6d32fba 100644
--- a/data/fonts/Roboto-Bold.ttf
+++ b/data/fonts/Roboto-Bold.ttf
Binary files differ
diff --git a/data/fonts/Roboto-BoldItalic.ttf b/data/fonts/Roboto-BoldItalic.ttf
index bf1fc1b..fc2da4c 100644
--- a/data/fonts/Roboto-BoldItalic.ttf
+++ b/data/fonts/Roboto-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Italic.ttf b/data/fonts/Roboto-Italic.ttf
index b204303..ce2e072 100644
--- a/data/fonts/Roboto-Italic.ttf
+++ b/data/fonts/Roboto-Italic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Regular.ttf b/data/fonts/Roboto-Regular.ttf
index 51cf896..465dfc1 100644
--- a/data/fonts/Roboto-Regular.ttf
+++ b/data/fonts/Roboto-Regular.ttf
Binary files differ
diff --git a/docs/html/sdk/android-4.0.jd b/docs/html/sdk/android-4.0.jd
index cad89c2..2ccc927 100644
--- a/docs/html/sdk/android-4.0.jd
+++ b/docs/html/sdk/android-4.0.jd
@@ -1910,7 +1910,6 @@
 <li>Search</li>
 <li>Settings</li>
 <li>Speech Recorder</li>
-<li>Speech Recorder</li>
 <li>Widget Preview</li>
 </ul>
 </td>
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index e98d55c..08835fb 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -209,7 +209,6 @@
             status_t        prepareAsync_l();
             status_t        getDuration_l(int *msec);
             status_t        attachNewPlayer(const sp<IMediaPlayer>& player);
-            void            disconnectNativeWindow();
             status_t        reset_l();
 
     sp<IMediaPlayer>            mPlayer;
@@ -233,8 +232,6 @@
     int                         mVideoHeight;
     int                         mAudioSessionId;
     float                       mSendLevel;
-    sp<ANativeWindow>           mConnectedWindow;
-    sp<IBinder>                 mConnectedWindowBinder;
 };
 
 }; // namespace android
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 37a82e9..f72300b 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -86,8 +86,6 @@
     if (p != 0) {
         p->disconnect();
     }
-
-    disconnectNativeWindow();
 }
 
 // always call with lock held
@@ -221,63 +219,12 @@
     return mPlayer->getMetadata(update_only, apply_filter, metadata);
 }
 
-void MediaPlayer::disconnectNativeWindow() {
-    if (mConnectedWindow != NULL) {
-        status_t err = native_window_api_disconnect(mConnectedWindow.get(),
-                NATIVE_WINDOW_API_MEDIA);
-
-        if (err != OK) {
-            LOGW("native_window_api_disconnect returned an error: %s (%d)",
-                    strerror(-err), err);
-        }
-    }
-    mConnectedWindow.clear();
-}
-
 status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
 {
     LOGV("setVideoSurface");
     Mutex::Autolock _l(mLock);
     if (mPlayer == 0) return NO_INIT;
-
-    sp<IBinder> binder(surface == NULL ? NULL : surface->asBinder());
-    if (mConnectedWindowBinder == binder) {
-        return OK;
-    }
-
-    if (surface != NULL) {
-        status_t err = native_window_api_connect(surface.get(),
-                NATIVE_WINDOW_API_MEDIA);
-
-        if (err != OK) {
-            LOGE("setVideoSurface failed: %d", err);
-            // Note that we must do the reset before disconnecting from the ANW.
-            // Otherwise queue/dequeue calls could be made on the disconnected
-            // ANW, which may result in errors.
-            reset_l();
-
-            disconnectNativeWindow();
-
-            return err;
-        }
-    }
-
-    // Note that we must set the player's new surface before disconnecting the
-    // old one.  Otherwise queue/dequeue calls could be made on the disconnected
-    // ANW, which may result in errors.
-    status_t err = mPlayer->setVideoSurface(surface);
-
-    disconnectNativeWindow();
-
-    mConnectedWindow = surface;
-
-    if (err == OK) {
-        mConnectedWindowBinder = binder;
-    } else {
-        disconnectNativeWindow();
-    }
-
-    return err;
+    return mPlayer->setVideoSurface(surface);
 }
 
 status_t MediaPlayer::setVideoSurfaceTexture(
@@ -286,48 +233,7 @@
     LOGV("setVideoSurfaceTexture");
     Mutex::Autolock _l(mLock);
     if (mPlayer == 0) return NO_INIT;
-
-    sp<IBinder> binder(surfaceTexture == NULL ? NULL :
-            surfaceTexture->asBinder());
-    if (mConnectedWindowBinder == binder) {
-        return OK;
-    }
-
-    sp<ANativeWindow> anw;
-    if (surfaceTexture != NULL) {
-        anw = new SurfaceTextureClient(surfaceTexture);
-        status_t err = native_window_api_connect(anw.get(),
-                NATIVE_WINDOW_API_MEDIA);
-
-        if (err != OK) {
-            LOGE("setVideoSurfaceTexture failed: %d", err);
-            // Note that we must do the reset before disconnecting from the ANW.
-            // Otherwise queue/dequeue calls could be made on the disconnected
-            // ANW, which may result in errors.
-            reset_l();
-
-            disconnectNativeWindow();
-
-            return err;
-        }
-    }
-
-    // Note that we must set the player's new SurfaceTexture before
-    // disconnecting the old one.  Otherwise queue/dequeue calls could be made
-    // on the disconnected ANW, which may result in errors.
-    status_t err = mPlayer->setVideoSurfaceTexture(surfaceTexture);
-
-    disconnectNativeWindow();
-
-    mConnectedWindow = anw;
-
-    if (err == OK) {
-        mConnectedWindowBinder = binder;
-    } else {
-        disconnectNativeWindow();
-    }
-
-    return err;
+    return mPlayer->setVideoSurfaceTexture(surfaceTexture);
 }
 
 // must call with lock held
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 2ea2af9..b655358 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -40,6 +40,7 @@
 #include <binder/IServiceManager.h>
 #include <binder/MemoryHeapBase.h>
 #include <binder/MemoryBase.h>
+#include <gui/SurfaceTextureClient.h>
 #include <utils/Errors.h>  // for status_t
 #include <utils/String8.h>
 #include <utils/SystemClock.h>
@@ -528,6 +529,8 @@
         p->reset();
     }
 
+    disconnectNativeWindow();
+
     IPCThreadState::self()->flushCommands();
 }
 
@@ -793,13 +796,67 @@
     return p->setVideoSurface(surface);
 }
 
+void MediaPlayerService::Client::disconnectNativeWindow() {
+    if (mConnectedWindow != NULL) {
+        status_t err = native_window_api_disconnect(mConnectedWindow.get(),
+                NATIVE_WINDOW_API_MEDIA);
+
+        if (err != OK) {
+            LOGW("native_window_api_disconnect returned an error: %s (%d)",
+                    strerror(-err), err);
+        }
+    }
+    mConnectedWindow.clear();
+}
+
 status_t MediaPlayerService::Client::setVideoSurfaceTexture(
         const sp<ISurfaceTexture>& surfaceTexture)
 {
     LOGV("[%d] setVideoSurfaceTexture(%p)", mConnId, surfaceTexture.get());
     sp<MediaPlayerBase> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
-    return p->setVideoSurfaceTexture(surfaceTexture);
+
+    sp<IBinder> binder(surfaceTexture == NULL ? NULL :
+            surfaceTexture->asBinder());
+    if (mConnectedWindowBinder == binder) {
+        return OK;
+    }
+
+    sp<ANativeWindow> anw;
+    if (surfaceTexture != NULL) {
+        anw = new SurfaceTextureClient(surfaceTexture);
+        status_t err = native_window_api_connect(anw.get(),
+                NATIVE_WINDOW_API_MEDIA);
+
+        if (err != OK) {
+            LOGE("setVideoSurfaceTexture failed: %d", err);
+            // Note that we must do the reset before disconnecting from the ANW.
+            // Otherwise queue/dequeue calls could be made on the disconnected
+            // ANW, which may result in errors.
+            reset();
+
+            disconnectNativeWindow();
+
+            return err;
+        }
+    }
+
+    // Note that we must set the player's new SurfaceTexture before
+    // disconnecting the old one.  Otherwise queue/dequeue calls could be made
+    // on the disconnected ANW, which may result in errors.
+    status_t err = p->setVideoSurfaceTexture(surfaceTexture);
+
+    disconnectNativeWindow();
+
+    mConnectedWindow = anw;
+
+    if (err == OK) {
+        mConnectedWindowBinder = binder;
+    } else {
+        disconnectNativeWindow();
+    }
+
+    return err;
 }
 
 status_t MediaPlayerService::Client::invoke(const Parcel& request,
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 53e625a..62214ba 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -318,6 +318,9 @@
         // @param type Of the metadata to be recorded.
         void addNewMetadataUpdate(media::Metadata::Type type);
 
+        // Disconnect from the currently connected ANativeWindow.
+        void disconnectNativeWindow();
+
         mutable     Mutex                       mLock;
                     sp<MediaPlayerBase>         mPlayer;
                     sp<MediaPlayerService>      mService;
@@ -329,6 +332,8 @@
                     int32_t                     mConnId;
                     int                         mAudioSessionId;
                     uid_t                       mUID;
+                    sp<ANativeWindow>           mConnectedWindow;
+                    sp<IBinder>                 mConnectedWindowBinder;
 
         // Metadata filters.
         media::Metadata::Filter mMetadataAllow;  // protected by mLock
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 4c710b4..7cdb76c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -796,7 +796,7 @@
         return;
     }
 
-    driver->sendEvent(msg, ext1, ext2);
+    driver->notifyListener(msg, ext1, ext2);
 }
 
 void NuPlayer::flushDecoder(bool audio, bool needShutdown) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index b1e917d..452ba99 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -35,6 +35,7 @@
       mNumFramesDropped(0),
       mLooper(new ALooper),
       mState(UNINITIALIZED),
+      mAtEOS(false),
       mStartupSeekTimeUs(-1) {
     mLooper->setName("NuPlayerDriver Looper");
 
@@ -106,7 +107,7 @@
 }
 
 status_t NuPlayerDriver::prepareAsync() {
-    sendEvent(MEDIA_PREPARED);
+    notifyListener(MEDIA_PREPARED);
 
     return OK;
 }
@@ -117,6 +118,7 @@
             return INVALID_OPERATION;
         case STOPPED:
         {
+            mAtEOS = false;
             mPlayer->start();
 
             if (mStartupSeekTimeUs >= 0) {
@@ -173,7 +175,7 @@
 }
 
 bool NuPlayerDriver::isPlaying() {
-    return mState == PLAYING;
+    return mState == PLAYING && !mAtEOS;
 }
 
 status_t NuPlayerDriver::seekTo(int msec) {
@@ -190,6 +192,7 @@
         case PLAYING:
         case PAUSED:
         {
+            mAtEOS = false;
             mPlayer->seekToAsync(seekTimeUs);
             break;
         }
@@ -291,7 +294,7 @@
 }
 
 void NuPlayerDriver::notifySeekComplete() {
-    sendEvent(MEDIA_SEEK_COMPLETE);
+    notifyListener(MEDIA_SEEK_COMPLETE);
 }
 
 void NuPlayerDriver::notifyFrameStats(
@@ -320,4 +323,12 @@
     return OK;
 }
 
+void NuPlayerDriver::notifyListener(int msg, int ext1, int ext2) {
+    if (msg == MEDIA_PLAYBACK_COMPLETE || msg == MEDIA_ERROR) {
+        mAtEOS = true;
+    }
+
+    sendEvent(msg, ext1, ext2);
+}
+
 }  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 181c37d..aaa3de0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -67,6 +67,7 @@
     void notifyPosition(int64_t positionUs);
     void notifySeekComplete();
     void notifyFrameStats(int64_t numFramesTotal, int64_t numFramesDropped);
+    void notifyListener(int msg, int ext1 = 0, int ext2 = 0);
 
 protected:
     virtual ~NuPlayerDriver();
@@ -95,6 +96,7 @@
     };
 
     State mState;
+    bool mAtEOS;
 
     int64_t mStartupSeekTimeUs;
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 79fcec0..8fba86a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -57,7 +57,7 @@
     <dimen name="status_bar_icon_drawing_size">18dip</dimen>
 
     <!-- opacity at which Notification icons will be drawn in the status bar -->
-    <item type="dimen" name="status_bar_icon_drawing_alpha">50%</item>
+    <item type="dimen" name="status_bar_icon_drawing_alpha">55%</item>
 
     <!-- gap on either side of status bar notification icons -->
     <dimen name="status_bar_icon_padding">0dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 9bee5df..5f18b5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -82,7 +82,7 @@
     private boolean mVolumeVisible;
 
     // bluetooth device status
-    private boolean mBluetoothEnabled;
+    private boolean mBluetoothEnabled = false;
 
     // wifi
     private static final int[][] sWifiSignalImages = {
@@ -139,6 +139,18 @@
         mContext = context;
         mService = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);
 
+        // listen for broadcasts
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_ALARM_CHANGED);
+        filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
+        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
+        filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
+        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+        filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
+        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
+        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
+
         // storage
         mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
         mStorageManager.registerListener(
@@ -153,13 +165,15 @@
         mService.setIconVisibility("cdma_eri", false);
 
         // bluetooth status
-        mService.setIcon("bluetooth", R.drawable.stat_sys_data_bluetooth, 0, null);
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        int bluetoothIcon = R.drawable.stat_sys_data_bluetooth;
         if (adapter != null) {
-            mBluetoothEnabled = adapter.isEnabled();
-        } else {
-            mBluetoothEnabled = false;
+            mBluetoothEnabled = (adapter.getState() == BluetoothAdapter.STATE_ON);
+            if (adapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED) {
+                bluetoothIcon = R.drawable.stat_sys_data_bluetooth_connected;
+            }
         }
+        mService.setIcon("bluetooth", bluetoothIcon, 0, null);
         mService.setIconVisibility("bluetooth", mBluetoothEnabled);
 
         // Alarm clock
@@ -176,19 +190,6 @@
         mService.setIcon("volume", R.drawable.stat_sys_ringer_silent, 0, null);
         mService.setIconVisibility("volume", false);
         updateVolume();
-
-        IntentFilter filter = new IntentFilter();
-
-        // Register for Intent broadcasts for...
-        filter.addAction(Intent.ACTION_ALARM_CHANGED);
-        filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
-        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
-        filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
-        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
-        filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
-        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
-        filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
-        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
     }
 
     private final void updateAlarm(Intent intent) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 3a06068..5e5bc1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -45,6 +45,7 @@
     private static final String TAG = "StatusBar.KeyButtonView";
 
     final float GLOW_MAX_SCALE_FACTOR = 1.8f;
+    final float BUTTON_QUIESCENT_ALPHA = 0.6f;
 
     IWindowManager mWindowManager;
     long mDownTime;
@@ -86,7 +87,7 @@
 
         mGlowBG = a.getDrawable(R.styleable.KeyButtonView_glowBackground);
         if (mGlowBG != null) {
-            mDrawingAlpha = 0.5f;
+            mDrawingAlpha = BUTTON_QUIESCENT_ALPHA;
         }
         
         a.recycle();
@@ -175,8 +176,10 @@
             if (pressed != isPressed()) {
                 AnimatorSet as = new AnimatorSet();
                 if (pressed) {
-                    if (mGlowScale < 1.7f) mGlowScale = 1.7f;
-                    if (mGlowAlpha < 0.5f) mGlowAlpha = 0.5f;
+                    if (mGlowScale < GLOW_MAX_SCALE_FACTOR) 
+                        mGlowScale = GLOW_MAX_SCALE_FACTOR;
+                    if (mGlowAlpha < BUTTON_QUIESCENT_ALPHA)
+                        mGlowAlpha = BUTTON_QUIESCENT_ALPHA;
                     setDrawingAlpha(1f);
                     as.playTogether(
                         ObjectAnimator.ofFloat(this, "glowAlpha", 1f),
@@ -187,7 +190,7 @@
                     as.playTogether(
                         ObjectAnimator.ofFloat(this, "glowAlpha", 0f),
                         ObjectAnimator.ofFloat(this, "glowScale", 1f),
-                        ObjectAnimator.ofFloat(this, "drawingAlpha", 0.5f)
+                        ObjectAnimator.ofFloat(this, "drawingAlpha", BUTTON_QUIESCENT_ALPHA)
                     );
                     as.setDuration(500);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HoloClock.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HoloClock.java
index 0121211..f98caa2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HoloClock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HoloClock.java
@@ -53,9 +53,9 @@
     private SimpleDateFormat mClockFormat;
 
     private static final String FONT_DIR = "/system/fonts/";
-    private static final String CLOCK_FONT = FONT_DIR + "AndroidClock_Solid.ttf"; 
-    private static final String CLOCK_FG_FONT = FONT_DIR + "AndroidClock.ttf"; 
-    private static final String CLOCK_BG_FONT = FONT_DIR + "AndroidClock_Highlight.ttf"; 
+    private static final String CLOCK_FONT = FONT_DIR + "AndroidClock_Solid.ttf";
+    private static final String CLOCK_FG_FONT = FONT_DIR + "AndroidClock.ttf";
+    private static final String CLOCK_BG_FONT = FONT_DIR + "AndroidClock_Highlight.ttf";
 
     private static Typeface sBackgroundType, sForegroundType, sSolidType;
     private TextView mSolidText, mBgText, mFgText;
@@ -84,7 +84,9 @@
         mBgText = (TextView) findViewById(R.id.time_bg);
         if (mBgText != null) {
             mBgText.setTypeface(sBackgroundType);
+            mBgText.setVisibility(View.INVISIBLE);
         }
+
         mFgText = (TextView) findViewById(R.id.time_fg);
         if (mFgText != null) {
             mFgText.setTypeface(sForegroundType);
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
index 6614d79..dafbdcf 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
@@ -635,11 +635,13 @@
      * @return
      */
     private static CharSequence makeCarierString(CharSequence plmn, CharSequence spn) {
-        if (plmn != null && spn == null) {
-            return plmn;
-        } else if (plmn != null && spn != null) {
+        final boolean plmnValid = !TextUtils.isEmpty(plmn);
+        final boolean spnValid = !TextUtils.isEmpty(spn);
+        if (plmnValid && spnValid) {
             return plmn + "|" + spn;
-        } else if (plmn == null && spn != null) {
+        } else if (plmnValid) {
+            return plmn;
+        } else if (spnValid) {
             return spn;
         } else {
             return "";
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 498bdfc..851cb33 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -2450,6 +2450,12 @@
         int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
         boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
+        // Short term disabling of Tethering if DUN is required.
+        // TODO - fix multi-connection tethering using policy-base routing
+        int[] upstreamConnTypes = mTethering.getUpstreamIfaceTypes();
+        for (int i : upstreamConnTypes) {
+            if (i == ConnectivityManager.TYPE_MOBILE_DUN) return false;
+        }
         return tetherEnabledInSettings && mTetheringConfigValid;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/IntRangeManager.java b/telephony/java/com/android/internal/telephony/IntRangeManager.java
index 970bc44..cc7774d 100644
--- a/telephony/java/com/android/internal/telephony/IntRangeManager.java
+++ b/telephony/java/com/android/internal/telephony/IntRangeManager.java
@@ -543,6 +543,14 @@
     }
 
     /**
+     * Returns whether the list of ranges is completely empty.
+     * @return true if there are no enabled ranges
+     */
+    public boolean isEmpty() {
+        return mRanges.isEmpty();
+    }
+
+    /**
      * Called when the list of enabled ranges has changed. This will be
      * followed by zero or more calls to {@link #addRange} followed by
      * a call to {@link #finishUpdate}.
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index e8d85de..9f93fb8 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1956,7 +1956,7 @@
 
         if (RILJ_LOGD) {
             riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
-                    + " with " + numOfConfig + "configs : ");
+                    + " with " + numOfConfig + " configs : ");
             for (int i = 0; i < numOfConfig; i++) {
                 riljLog(config[i].toString());
             }
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java
index 8d0e5d3..92bf390 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java
@@ -246,6 +246,8 @@
             log("Added cell broadcast subscription for MID range " + startMessageId
                     + " to " + endMessageId + " from client " + client);
 
+        setCellBroadcastActivation(!mCellBroadcastRangeManager.isEmpty());
+
         return true;
     }
 
@@ -271,6 +273,8 @@
             log("Removed cell broadcast subscription for MID range " + startMessageId
                     + " to " + endMessageId + " from client " + client);
 
+        setCellBroadcastActivation(!mCellBroadcastRangeManager.isEmpty());
+
         return true;
     }
 
@@ -301,14 +305,15 @@
         /**
          * Called to indicate the end of a range update started by the
          * previous call to {@link #startUpdate}.
+         * @return true if successful, false otherwise
          */
         protected boolean finishUpdate() {
             if (mConfigList.isEmpty()) {
-                return setCellBroadcastActivation(false);
+                return true;
             } else {
                 SmsBroadcastConfigInfo[] configs =
                         mConfigList.toArray(new SmsBroadcastConfigInfo[mConfigList.size()]);
-                return setCellBroadcastConfig(configs) && setCellBroadcastActivation(true);
+                return setCellBroadcastConfig(configs);
             }
         }
     }
diff --git a/tests/FrameworkPerf/Android.mk b/tests/FrameworkPerf/Android.mk
new file mode 100644
index 0000000..03893d6
--- /dev/null
+++ b/tests/FrameworkPerf/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := FrameworkPerf
+
+LOCAL_AAPT_FLAGS = -c 120dpi,240dpi,160dpi,161dpi,320dpi,nodpi
+
+include $(BUILD_PACKAGE)
diff --git a/tests/FrameworkPerf/AndroidManifest.xml b/tests/FrameworkPerf/AndroidManifest.xml
new file mode 100644
index 0000000..f69d550
--- /dev/null
+++ b/tests/FrameworkPerf/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.frameworkperf">
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-sdk android:minSdkVersion="5" />
+
+    <application>
+        <activity android:name="FrameworkPerfActivity" android:label="Framework Perf">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <service android:name="SchedulerService">
+        </service>
+    </application>
+</manifest>
diff --git a/tests/FrameworkPerf/res/drawable-161dpi/stat_sample_scale.png b/tests/FrameworkPerf/res/drawable-161dpi/stat_sample_scale.png
new file mode 100755
index 0000000..6c9ba0a
--- /dev/null
+++ b/tests/FrameworkPerf/res/drawable-161dpi/stat_sample_scale.png
Binary files differ
diff --git a/tests/FrameworkPerf/res/drawable-161dpi/wallpaper_goldengate_scale.jpg b/tests/FrameworkPerf/res/drawable-161dpi/wallpaper_goldengate_scale.jpg
new file mode 100644
index 0000000..2271091
--- /dev/null
+++ b/tests/FrameworkPerf/res/drawable-161dpi/wallpaper_goldengate_scale.jpg
Binary files differ
diff --git a/tests/FrameworkPerf/res/drawable-hdpi/stat_happy.png b/tests/FrameworkPerf/res/drawable-hdpi/stat_happy.png
new file mode 100755
index 0000000..27f5bb7
--- /dev/null
+++ b/tests/FrameworkPerf/res/drawable-hdpi/stat_happy.png
Binary files differ
diff --git a/tests/FrameworkPerf/res/drawable-mdpi/stat_happy.png b/tests/FrameworkPerf/res/drawable-mdpi/stat_happy.png
new file mode 100644
index 0000000..3a8791b
--- /dev/null
+++ b/tests/FrameworkPerf/res/drawable-mdpi/stat_happy.png
Binary files differ
diff --git a/tests/FrameworkPerf/res/drawable-nodpi/stat_sample.png b/tests/FrameworkPerf/res/drawable-nodpi/stat_sample.png
new file mode 100755
index 0000000..6c9ba0a
--- /dev/null
+++ b/tests/FrameworkPerf/res/drawable-nodpi/stat_sample.png
Binary files differ
diff --git a/tests/FrameworkPerf/res/drawable-nodpi/wallpaper_goldengate.jpg b/tests/FrameworkPerf/res/drawable-nodpi/wallpaper_goldengate.jpg
new file mode 100644
index 0000000..2271091
--- /dev/null
+++ b/tests/FrameworkPerf/res/drawable-nodpi/wallpaper_goldengate.jpg
Binary files differ
diff --git a/tests/FrameworkPerf/res/layout/large_layout.xml b/tests/FrameworkPerf/res/layout/large_layout.xml
new file mode 100644
index 0000000..b6ac88c
--- /dev/null
+++ b/tests/FrameworkPerf/res/layout/large_layout.xml
@@ -0,0 +1,460 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<!-- All ids in this layout must be in wifi_dialog.xml -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <!-- UI components that should be shown appropriately -->
+    <FrameLayout
+        android:id="@+id/eap_not_supported"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="360dip"
+        android:orientation="vertical"
+        android:visibility="gone">
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:lineSpacingExtra="12dip"
+            android:text="Foo"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="20sp" />
+    </FrameLayout>
+    <!-- In "add network" flow, we have security type field (@id/security below) below
+         this View, so need a bit different layout than the other flow, in which we'll use
+         @id/eap_not_supported. -->
+    <FrameLayout
+        android:id="@+id/eap_not_supported_for_add_network"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:visibility="gone">
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:lineSpacingExtra="12dip"
+            android:text="Bar"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="20sp" />
+    </FrameLayout>
+    <LinearLayout
+        android:id="@+id/wps_fields"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:visibility="gone">
+        <TextView
+            android:layout_width="match_parent"
+            android:minWidth="128dip"
+            android:layout_height="wrap_content"
+            android:text="Blah"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="20sp"
+            android:gravity="bottom" />
+
+        <EditText
+            android:id="@+id/wps_pin"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:inputType="textPassword"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="20sp" />
+    </LinearLayout>
+    <TableLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="16dip">
+        <!-- To accomodate @id/type into TableLayout, we splitted the layout into two:
+             @id/type_ssid and @id/type_security. -->
+        <TableRow
+            android:id="@+id/type_ssid"
+            android:minHeight="56dip"
+            android:visibility="gone">
+            <TextView
+                android:id="@+id/ssid_text"
+                android:layout_width="wrap_content"
+                android:minWidth="128dip"
+                android:layout_height="wrap_content"
+                android:minHeight="56dip"
+                android:paddingRight="16dip"
+                android:layout_alignParentLeft="true"
+                android:text="Whatever"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+                android:textSize="20sp"
+                android:gravity="left|center_vertical" />
+
+            <FrameLayout
+                android:id="@+id/ssid_layout"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignBottom="@id/ssid_text"
+                android:layout_toRightOf="@id/ssid_text">
+                <EditText
+                    android:id="@+id/ssid"
+                    android:layout_width="368dip"
+                    android:layout_height="wrap_content"
+                    android:singleLine="true"
+                    android:inputType="textNoSuggestions"
+                    android:textAppearance="?android:attr/textAppearanceMedium"
+                    android:textSize="20sp" />
+            </FrameLayout>
+        </TableRow>
+
+        <TableRow
+            android:id="@+id/security_fields"
+            android:minHeight="56dip"
+            android:visibility="gone">
+            <TextView
+                android:id="@+id/password_text"
+                android:layout_width="wrap_content"
+                android:minWidth="128dip"
+                android:layout_height="wrap_content"
+                android:minHeight="56dip"
+                android:text="Whenever"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+                android:textSize="20sp"
+                android:gravity="left|center_vertical" />
+
+            <LinearLayout
+                android:id="@+id/password_layout"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="bottom">
+                <EditText
+                    android:id="@+id/password"
+                    android:layout_width="368dip"
+                    android:layout_height="wrap_content"
+                    android:minHeight="56dip"
+                    android:singleLine="true"
+                    android:password="true"
+                    android:textAppearance="?android:attr/textAppearanceMedium"
+                    android:textSize="20sp" />
+            </LinearLayout>
+
+            <!-- It looks CheckBox isn't aligned well with TableRow -->
+            <FrameLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content">
+                <CheckBox
+                    android:id="@+id/show_password"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:minHeight="56dip"
+                    android:text="However"
+                    android:textAppearance="?android:attr/textAppearanceMedium"
+                    android:textSize="20sp" />
+            </FrameLayout>
+        </TableRow>
+
+        <TableRow
+            android:id="@+id/type_security"
+            android:minHeight="56dip"
+            android:visibility="gone">
+            <TextView
+                android:id="@+id/security_text"
+                android:layout_width="wrap_content"
+                android:minWidth="128dip"
+                android:layout_height="wrap_content"
+                android:minHeight="56dip"
+                android:text="Whoever"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+                android:textSize="20sp"
+                android:gravity="bottom"/>
+
+            <FrameLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="bottom">
+                <Spinner
+                    android:id="@+id/security"
+                    android:layout_width="368dip"
+                    android:layout_height="wrap_content"
+                    android:minHeight="56dip"
+                    android:paddingLeft="4dip"/>
+            </FrameLayout>
+        </TableRow>
+    </TableLayout>
+
+    <!-- All the views below are "gone".
+         We want them as data storage, not as UI components. -->
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone">
+
+    <LinearLayout android:id="@+id/info"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical"/>
+
+    <LinearLayout android:id="@+id/setup_fields"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical"
+                  android:visibility="gone">
+
+        <TextView
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:text="On the top" />
+
+        <Spinner android:id="@+id/network_setup"
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content" />
+
+    </LinearLayout>
+
+    <!--  android:id="@+id/security_fields" -->
+    <LinearLayout
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical"
+                  android:visibility="gone">
+
+        <LinearLayout android:id="@+id/eap"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:orientation="vertical"
+                      android:visibility="gone">
+
+            <TextView
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:text="On the bottom" />
+
+            <Spinner android:id="@+id/method"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content" />
+
+            <TextView
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:text="On the side" />
+
+            <Spinner android:id="@+id/phase2"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content" />
+
+            <TextView
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:text="SRH" />
+
+            <Spinner android:id="@+id/ca_cert"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content" />
+
+            <TextView
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:text="Enjoyable" />
+
+            <Spinner android:id="@+id/user_cert"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content" />
+
+            <TextView
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:text="Fantastic" />
+
+            <EditText android:id="@+id/identity"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:singleLine="true"
+                      android:inputType="textNoSuggestions" />
+
+            <TextView
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:text="Superb" />
+
+            <EditText android:id="@+id/anonymous"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:singleLine="true"
+                      android:inputType="textNoSuggestions" />
+        </LinearLayout> <!-- android:id="@+id/eap" -->
+
+        <!-- <TextView android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:text="@string/wifi_password" />
+
+        <EditText android:id="@+id/password"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:singleLine="true"
+                  android:password="true" />
+
+        <CheckBox android:id="@+id/show_password"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:text="@string/wifi_show_password" /> -->
+    </LinearLayout>  <!-- android:id="@+id/security_fields" -->
+
+        <LinearLayout android:id="@+id/proxy_settings_fields"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:visibility="gone">
+
+            <TextView android:id="@+id/proxy_settings_title"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="Heavenly" />
+
+            <Spinner android:id="@+id/proxy_settings"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content" />
+        </LinearLayout>
+
+        <LinearLayout android:id="@+id/proxy_warning_limited_support"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical"
+                  android:visibility="gone">
+
+                <!--  Dummy to enable right-justification of warning -->
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content" />
+
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="Orgasmic" />
+        </LinearLayout>
+
+        <LinearLayout android:id="@+id/proxy_fields"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:visibility="gone">
+            <TextView android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="Really" />
+
+            <EditText android:id="@+id/proxy_hostname"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:singleLine="true"
+                    android:inputType="textNoSuggestions" />
+
+            <TextView android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="Really really" />
+
+            <EditText android:id="@+id/proxy_port"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:singleLine="true"
+                    android:inputType="textNoSuggestions" />
+
+            <TextView android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="Really really with cherries on top" />
+
+            <EditText android:id="@+id/proxy_exclusionlist"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:singleLine="true"
+                    android:inputType="textNoSuggestions" />
+
+        </LinearLayout>
+
+        <LinearLayout android:id="@+id/ip_fields"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:visibility="gone">
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="Mmmmm... cherries" />
+
+            <Spinner android:id="@+id/ip_settings"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+        </LinearLayout>
+
+        <LinearLayout android:id="@+id/staticip"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:visibility="gone">
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="I mean Mmmmm.. cherries" />
+
+            <EditText android:id="@+id/ipaddress"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:inputType="textNoSuggestions" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="Shorter" />
+
+            <EditText android:id="@+id/gateway"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:inputType="textNoSuggestions" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="is" />
+
+            <EditText android:id="@+id/network_prefix_length"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:inputType="textNoSuggestions" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="better" />
+
+            <EditText android:id="@+id/dns1"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:inputType="textNoSuggestions" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="always" />
+
+            <EditText android:id="@+id/dns2"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:inputType="textNoSuggestions" />
+
+        </LinearLayout>
+    </LinearLayout>
+</LinearLayout>
diff --git a/tests/FrameworkPerf/res/layout/main.xml b/tests/FrameworkPerf/res/layout/main.xml
new file mode 100644
index 0000000..2e9c500
--- /dev/null
+++ b/tests/FrameworkPerf/res/layout/main.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    >
+
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        >
+        <Button android:id="@+id/start"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/start"
+            />
+        <Button android:id="@+id/stop"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/stop"
+            />
+    </LinearLayout>
+
+    <ScrollView android:id="@+id/scroll"
+        android:layout_width="match_parent"
+        android:layout_height="0px"
+        android:layout_weight="1"
+        >
+        <TextView android:id="@+id/log"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="25dp"
+            android:textSize="12sp"
+            android:textColor="#ffffffff"
+            />
+    </ScrollView>
+
+</LinearLayout>
diff --git a/tests/FrameworkPerf/res/layout/small_layout.xml b/tests/FrameworkPerf/res/layout/small_layout.xml
new file mode 100644
index 0000000..9fcbb26
--- /dev/null
+++ b/tests/FrameworkPerf/res/layout/small_layout.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+
+    <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content">
+
+        <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content">
+                <TextView android:text="Foo" android:layout_width="wrap_content" android:layout_height="wrap_content" />
+        </LinearLayout>
+
+        <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content">
+                <TextView android:id="@+id/config_list" android:layout_width="wrap_content" android:layout_height="wrap_content" />
+        </LinearLayout>
+    </LinearLayout>
+
+</ScrollView>
+
diff --git a/tests/FrameworkPerf/res/values/attrs.xml b/tests/FrameworkPerf/res/values/attrs.xml
new file mode 100644
index 0000000..5823537
--- /dev/null
+++ b/tests/FrameworkPerf/res/values/attrs.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<resources>
+    <!-- Base attributes that are available to all Item objects. -->
+    <declare-styleable name="MenuItem">
+
+        <!-- The ID of the item. -->
+        <attr name="android:id" />
+
+        <!-- The category applied to the item.
+             (This will be or'ed with the orderInCategory attribute.) -->
+        <attr name="android:menuCategory" />
+
+        <!-- The order within the category applied to the item.
+             (This will be or'ed with the category attribute.) -->
+        <attr name="android:orderInCategory" />
+
+        <!-- The title associated with the item. -->
+        <attr name="android:title" />
+
+        <!-- The condensed title associated with the item.  This is used in situations where the
+             normal title may be too long to be displayed. -->
+        <attr name="android:titleCondensed" />
+
+        <!-- The icon associated with this item.  This icon will not always be shown, so
+             the title should be sufficient in describing this item. -->
+        <attr name="android:icon" />
+
+        <!-- The alphabetic shortcut key.  This is the shortcut when using a keyboard
+             with alphabetic keys. -->
+        <attr name="android:alphabeticShortcut" />
+
+        <!-- The numeric shortcut key.  This is the shortcut when using a numeric (e.g., 12-key)
+             keyboard. -->
+        <attr name="android:numericShortcut" />
+
+        <!-- Whether the item is capable of displaying a check mark. -->
+        <attr name="android:checkable" />
+
+        <!-- Whether the item is checked.  Note that you must first have enabled checking with
+             the checkable attribute or else the check mark will not appear. -->
+        <attr name="android:checked" />
+
+        <!-- Whether the item is shown/visible. -->
+        <attr name="android:visible" />
+
+        <!-- Whether the item is enabled. -->
+        <attr name="android:enabled" />
+    </declare-styleable>
+</resources>
diff --git a/tests/FrameworkPerf/res/values/strings.xml b/tests/FrameworkPerf/res/values/strings.xml
new file mode 100644
index 0000000..82fd713
--- /dev/null
+++ b/tests/FrameworkPerf/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<resources>
+    <string name="start">Start</string>
+    <string name="stop">Stop</string>
+    <string name="data_usage_menu_roaming">Data roaming</string>
+    <string name="data_usage_menu_restrict_background">Restrict background data</string>
+    <string name="data_usage_menu_split_4g">Separate 4G usage</string>
+    <string name="data_usage_menu_show_wifi">Show Wi-Fi usage</string>
+    <string name="data_usage_menu_show_ethernet">Show Ethernet usage</string>
+</resources>
diff --git a/tests/FrameworkPerf/res/xml/simple.xml b/tests/FrameworkPerf/res/xml/simple.xml
new file mode 100644
index 0000000..4e938aa
--- /dev/null
+++ b/tests/FrameworkPerf/res/xml/simple.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+</menu>
diff --git a/tests/FrameworkPerf/res/xml/simple_large.xml b/tests/FrameworkPerf/res/xml/simple_large.xml
new file mode 100644
index 0000000..812cec9
--- /dev/null
+++ b/tests/FrameworkPerf/res/xml/simple_large.xml
@@ -0,0 +1,418 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_roaming"
+        android:title="@string/data_usage_menu_roaming"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_restrict_background"
+        android:title="@string/data_usage_menu_restrict_background"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_split_4g"
+        android:title="@string/data_usage_menu_split_4g"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_wifi"
+        android:title="@string/data_usage_menu_show_wifi"
+        android:checkable="true" />
+    <item
+        android:id="@+id/data_usage_menu_show_ethernet"
+        android:title="@string/data_usage_menu_show_ethernet"
+        android:checkable="true" />
+</menu>
diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java b/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java
new file mode 100644
index 0000000..9f05a55
--- /dev/null
+++ b/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java
@@ -0,0 +1,694 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworkperf;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.SystemClock;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+/**
+ * So you thought sync used up your battery life.
+ */
+public class FrameworkPerfActivity extends Activity {
+    final Handler mHandler = new Handler();
+
+    TextView mLog;
+    PowerManager.WakeLock mPartialWakeLock;
+
+    long mMaxRunTime = 5000;
+    boolean mStarted;
+
+    final TestRunner mRunner = new TestRunner();
+
+    final Op[] mOpPairs = new Op[] {
+            new MethodCallOp(), new NoOp(),
+            new MethodCallOp(), new CpuOp(),
+            new MethodCallOp(), new SchedulerOp(),
+            new MethodCallOp(), new GcOp(),
+            new SchedulerOp(), new SchedulerOp(),
+            new GcOp(), new NoOp(),
+            new IpcOp(), new NoOp(),
+            new IpcOp(), new CpuOp(),
+            new IpcOp(), new SchedulerOp(),
+            new IpcOp(), new GcOp(),
+            new ParseXmlResOp(), new NoOp(),
+            new ParseLargeXmlResOp(), new NoOp(),
+            new LayoutInflaterOp(), new NoOp(),
+            new LayoutInflaterLargeOp(), new NoOp(),
+            new LoadSmallBitmapOp(), new NoOp(),
+            new LoadLargeBitmapOp(), new NoOp(),
+            new LoadSmallScaledBitmapOp(), new NoOp(),
+            new LoadLargeScaledBitmapOp(), new NoOp(),
+    };
+
+    final Op[] mAvailOps = new Op[] {
+            new NoOp(),
+            new CpuOp(),
+            new SchedulerOp(),
+            new MethodCallOp(),
+            new IpcOp(),
+            new ParseXmlResOp(),
+            new ParseLargeXmlResOp(),
+            new LoadSmallBitmapOp(),
+            new LoadLargeBitmapOp(),
+            new LoadSmallScaledBitmapOp(),
+            new LoadLargeScaledBitmapOp(),
+    };
+    
+    int mCurOpIndex = 0;
+
+    class RunResult {
+        final String name;
+        final String fgLongName;
+        final String bgLongName;
+        final long fgTime;
+        final long fgOps;
+        final long bgTime;
+        final long bgOps;
+
+        RunResult(TestRunner op) {
+            name = op.getName();
+            fgLongName = op.getForegroundLongName();
+            bgLongName = op.getBackgroundLongName();
+            fgTime = op.getForegroundTime();
+            fgOps = op.getForegroundOps();
+            bgTime = op.getBackgroundTime();
+            bgOps = op.getBackgroundOps();
+        }
+
+        float getFgMsPerOp() {
+            return fgOps != 0 ? (fgTime / (float)fgOps) : 0;
+        }
+
+        float getBgMsPerOp() {
+            return bgOps != 0 ? (bgTime / (float)bgOps) : 0;
+        }
+    }
+
+    final ArrayList<RunResult> mResults = new ArrayList<RunResult>();
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Set the layout for this activity.  You can find it
+        // in res/layout/hello_activity.xml
+        setContentView(R.layout.main);
+
+        findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
+            @Override public void onClick(View v) {
+                startRunning();
+            }
+        });
+        findViewById(R.id.stop).setOnClickListener(new View.OnClickListener() {
+            @Override public void onClick(View v) {
+                stopRunning();
+            }
+        });
+        mLog = (TextView)findViewById(R.id.log);
+
+        PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE);
+        mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Scheduler");
+        mPartialWakeLock.setReferenceCounted(false);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        stopRunning();
+        if (mPartialWakeLock.isHeld()) {
+            mPartialWakeLock.release();
+        }
+    }
+
+    void startCurOp() {
+        mRunner.run(mHandler, mOpPairs[mCurOpIndex], mOpPairs[mCurOpIndex+1], new Runnable() {
+            @Override public void run() {
+                RunResult result = new RunResult(mRunner);
+                log(String.format("%s: fg=%d*%gms/op (%dms) / bg=%d*%gms/op (%dms)",
+                        result.name, result.fgOps, result.getFgMsPerOp(), result.fgTime,
+                        result.bgOps, result.getBgMsPerOp(), result.bgTime));
+                mResults.add(result);
+                if (!mStarted) {
+                    log("Stop");
+                    stopRunning();
+                    return;
+                }
+                mCurOpIndex+=2;
+                if (mCurOpIndex >= mOpPairs.length) {
+                    log("Finished");
+                    stopRunning();
+                    return;
+                }
+                startCurOp();
+            }
+        });
+    }
+
+    void startRunning() {
+        if (!mStarted) {
+            log("Start");
+            mStarted = true;
+            updateWakeLock();
+            startService(new Intent(this, SchedulerService.class));
+            mCurOpIndex = 0;
+            mResults.clear();
+            startCurOp();
+        }
+    }
+
+    void stopRunning() {
+        if (mStarted) {
+            mStarted = false;
+            updateWakeLock();
+            stopService(new Intent(this, SchedulerService.class));
+            for (int i=0; i<mResults.size(); i++) {
+                RunResult result = mResults.get(i);
+                float fgMsPerOp = result.getFgMsPerOp();
+                float bgMsPerOp = result.getBgMsPerOp();
+                String fgMsPerOpStr = fgMsPerOp != 0 ? Float.toString(fgMsPerOp) : "";
+                String bgMsPerOpStr = bgMsPerOp != 0 ? Float.toString(bgMsPerOp) : "";
+                Log.i("Perf", "\t" + result.name + "\t" + result.fgOps
+                        + "\t" + result.getFgMsPerOp() + "\t" + result.fgTime
+                        + "\t" + result.fgLongName + "\t" + result.bgOps
+                        + "\t" + result.getBgMsPerOp() + "\t" + result.bgTime
+                        + "\t" + result.bgLongName);
+            }
+        }
+    }
+
+    void updateWakeLock() {
+        if (mStarted) {
+            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+            if (!mPartialWakeLock.isHeld()) {
+                mPartialWakeLock.acquire();
+            }
+        } else {
+            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+            if (mPartialWakeLock.isHeld()) {
+                mPartialWakeLock.release();
+            }
+        }
+    }
+
+    void log(String s) {
+        mLog.setText(mLog.getText() + "\n" + s);
+        Log.i("Perf", s);
+    }
+
+    enum BackgroundMode {
+        NOTHING,
+        CPU,
+        SCHEDULER
+    };
+
+    public class TestRunner {
+        Handler mHandler;
+        Op mForegroundOp;
+        Op mBackgroundOp;
+        Runnable mDoneCallback;
+
+        RunnerThread mBackgroundThread;
+        RunnerThread mForegroundThread;
+        long mStartTime;
+
+        boolean mBackgroundRunning;
+        boolean mForegroundRunning;
+
+        long mBackgroundEndTime;
+        long mBackgroundOps;
+        long mForegroundEndTime;
+        long mForegroundOps;
+
+        public TestRunner() {
+        }
+
+        public String getForegroundName() {
+            return mForegroundOp.getName();
+        }
+
+        public String getBackgroundName() {
+            return mBackgroundOp.getName();
+        }
+
+        public String getName() {
+            String fgName = mForegroundOp.getName();
+            String bgName = mBackgroundOp.getName();
+            StringBuilder res = new StringBuilder();
+            if (fgName != null) {
+                res.append(fgName);
+                res.append("Fg");
+            }
+            if (bgName != null) {
+                res.append(bgName);
+                res.append("Bg");
+            }
+            return res.toString();
+        }
+
+        public String getForegroundLongName() {
+            return mForegroundOp.getLongName();
+        }
+
+        public String getBackgroundLongName() {
+            return mBackgroundOp.getLongName();
+        }
+
+        public void run(Handler handler, Op foreground, Op background, Runnable doneCallback) {
+            mHandler = handler;
+            mForegroundOp = foreground;
+            mBackgroundOp = background;
+            mDoneCallback = doneCallback;
+            mBackgroundThread = new RunnerThread("background", new Runnable() {
+                @Override public void run() {
+                    boolean running;
+                    int ops = 0;
+                    do {
+                        running = mBackgroundOp.onRun();
+                        ops++;
+                    } while (evalRepeat(running, true) && running);
+                    mBackgroundEndTime = SystemClock.uptimeMillis();
+                    mBackgroundOps = ops * mBackgroundOp.getOpsPerRun();
+                    threadFinished(false);
+                }
+            }, Process.THREAD_PRIORITY_BACKGROUND);
+            mForegroundThread = new RunnerThread("background", new Runnable() {
+                @Override public void run() {
+                    boolean running;
+                    int ops = 0;
+                    do {
+                        running = mForegroundOp.onRun();
+                        ops++;
+                    } while (evalRepeat(true, running) && running);
+                    mForegroundEndTime = SystemClock.uptimeMillis();
+                    mForegroundOps = ops * mForegroundOp.getOpsPerRun();
+                    threadFinished(true);
+                }
+            }, Process.THREAD_PRIORITY_FOREGROUND);
+
+            mForegroundOp.onInit(FrameworkPerfActivity.this);
+            mBackgroundOp.onInit(FrameworkPerfActivity.this);
+
+            synchronized (this) {
+                mStartTime = SystemClock.uptimeMillis();
+                mBackgroundRunning = true;
+                mForegroundRunning = true;
+            }
+
+            mBackgroundThread.start();
+            mForegroundThread.start();
+        }
+
+        public long getForegroundTime() {
+            return mForegroundEndTime-mStartTime;
+        }
+
+        public long getForegroundOps() {
+            return mForegroundOps;
+        }
+
+        public long getBackgroundTime() {
+            return mBackgroundEndTime-mStartTime;
+        }
+
+        public long getBackgroundOps() {
+            return mBackgroundOps;
+        }
+
+        private boolean evalRepeat(boolean bgRunning, boolean fgRunning) {
+            synchronized (this) {
+                if (!bgRunning) {
+                    mBackgroundRunning = false;
+                }
+                if (!fgRunning) {
+                    mForegroundRunning = false;
+                }
+                if (!mBackgroundRunning && !mForegroundRunning) {
+                    return false;
+                }
+                long now = SystemClock.uptimeMillis();
+                if (now > (mStartTime+mMaxRunTime)) {
+                    return false;
+                }
+                return true;
+            }
+        }
+
+        private void threadFinished(boolean foreground) {
+            synchronized (this) {
+                if (foreground) {
+                    mForegroundRunning = false;
+                } else {
+                    mBackgroundRunning = false;
+                }
+                if (!mBackgroundRunning && !mForegroundRunning) {
+                    mHandler.post(new Runnable() {
+                        @Override public void run() {
+                            if (mDoneCallback != null) {
+                                mDoneCallback.run();
+                            }
+                        }
+                    });
+                }
+            }
+        }
+    }
+
+    class RunnerThread extends Thread {
+        private final Runnable mOp;
+        private final int mPriority;
+
+        RunnerThread(String name, Runnable op, int priority) {
+            super(name);
+            mOp = op;
+            mPriority = priority;
+        }
+
+        public void run() {
+            Process.setThreadPriority(mPriority);
+            mOp.run();
+        }
+    }
+
+    static public abstract class Op {
+        final String mName;
+        final String mLongName;
+
+        public Op(String name, String longName) {
+            mName = name;
+            mLongName = longName;
+        }
+
+        public String getName() {
+            return mName;
+        }
+
+        public String getLongName() {
+            return mLongName;
+        }
+
+        void onInit(Context context) {
+        }
+
+        abstract boolean onRun();
+
+        int getOpsPerRun() {
+            return 1;
+        }
+    }
+
+    static class NoOp extends Op {
+        NoOp() {
+            super(null, "Nothing");
+        }
+
+        boolean onRun() {
+            return false;
+        }
+
+        int getOpsPerRun() {
+            return 0;
+        }
+    }
+
+    static class CpuOp extends Op {
+        CpuOp() {
+            super("CPU", "Consume CPU");
+        }
+
+        boolean onRun() {
+            return true;
+        }
+    }
+
+    static class SchedulerOp extends Op {
+        SchedulerOp() {
+            super("Sched", "Change scheduler group");
+        }
+
+        boolean onRun() {
+            Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
+            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+            return true;
+        }
+    }
+
+    static class GcOp extends Op {
+        GcOp() {
+            super("Gc", "Run garbage collector");
+        }
+
+        boolean onRun() {
+            byte[] stuff = new byte[1024*1024];
+            return true;
+        }
+    }
+
+    static class MethodCallOp extends Op {
+        MethodCallOp() {
+            super("MethodCall", "Method call");
+        }
+
+        boolean onRun() {
+            final int N = getOpsPerRun();
+            for (int i=0; i<N; i++) {
+                someFunc(i);
+            }
+            return true;
+        }
+
+        int someFunc(int foo) {
+            return 0;
+        }
+
+        int getOpsPerRun() {
+            return 500;
+        }
+    }
+
+    static class IpcOp extends Op {
+        PackageManager mPm;
+        String mProcessName;
+
+        IpcOp() {
+            super("Ipc", "IPC to system process");
+        }
+
+        void onInit(Context context) {
+            mPm = context.getPackageManager();
+            mProcessName = context.getApplicationInfo().processName;
+        }
+
+        boolean onRun() {
+            final int N = getOpsPerRun();
+            for (int i=0; i<N; i++) {
+                mPm.queryContentProviders(mProcessName, Process.myUid(), 0);
+            }
+            return true;
+        }
+
+        int getOpsPerRun() {
+            return 100;
+        }
+    }
+
+    static class ParseXmlResOp extends Op {
+        Context mContext;
+
+        ParseXmlResOp() {
+            super("ParseXmlRes", "Parse compiled XML resource");
+        }
+
+        void onInit(Context context) {
+            mContext = context;
+        }
+
+        boolean onRun() {
+            SimpleInflater inf = new SimpleInflater(mContext);
+            inf.inflate(R.xml.simple);
+            return true;
+        }
+    }
+
+    static class ParseLargeXmlResOp extends Op {
+        Context mContext;
+
+        ParseLargeXmlResOp() {
+            super("ParseLargeXmlRes", "Parse large XML resource");
+        }
+
+        void onInit(Context context) {
+            mContext = context;
+        }
+
+        boolean onRun() {
+            SimpleInflater inf = new SimpleInflater(mContext);
+            inf.inflate(R.xml.simple_large);
+            return true;
+        }
+    }
+
+    static class LayoutInflaterOp extends Op {
+        Context mContext;
+
+        LayoutInflaterOp() {
+            super("LayoutInflaterOp", "Inflate layout resource");
+        }
+
+        void onInit(Context context) {
+            mContext = context;
+        }
+
+        boolean onRun() {
+            if (Looper.myLooper() == null) {
+                Looper.prepare();
+            }
+            LayoutInflater inf = (LayoutInflater)mContext.getSystemService(
+                    Context.LAYOUT_INFLATER_SERVICE);
+            inf.inflate(R.layout.small_layout, null);
+            return true;
+        }
+    }
+
+    static class LayoutInflaterLargeOp extends Op {
+        Context mContext;
+
+        LayoutInflaterLargeOp() {
+            super("LayoutInflaterLargeOp", "Inflate large layout resource");
+        }
+
+        void onInit(Context context) {
+            mContext = context;
+        }
+
+        boolean onRun() {
+            if (Looper.myLooper() == null) {
+                Looper.prepare();
+            }
+            LayoutInflater inf = (LayoutInflater)mContext.getSystemService(
+                    Context.LAYOUT_INFLATER_SERVICE);
+            inf.inflate(R.layout.large_layout, null);
+            return true;
+        }
+    }
+
+    static class LoadSmallBitmapOp extends Op {
+        Context mContext;
+
+        LoadSmallBitmapOp() {
+            super("LoadSmallBitmap", "Load small raw bitmap");
+        }
+
+        void onInit(Context context) {
+            mContext = context;
+        }
+
+        boolean onRun() {
+            BitmapFactory.Options opts = new BitmapFactory.Options();
+            opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
+            Bitmap bm = BitmapFactory.decodeResource(mContext.getResources(),
+                    R.drawable.stat_sample, opts);
+            bm.recycle();
+            return true;
+        }
+    }
+
+    static class LoadLargeBitmapOp extends Op {
+        Context mContext;
+
+        LoadLargeBitmapOp() {
+            super("LoadLargeBitmap", "Load large raw bitmap");
+        }
+
+        void onInit(Context context) {
+            mContext = context;
+        }
+
+        boolean onRun() {
+            BitmapFactory.Options opts = new BitmapFactory.Options();
+            opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
+            Bitmap bm = BitmapFactory.decodeResource(mContext.getResources(),
+                    R.drawable.wallpaper_goldengate, opts);
+            bm.recycle();
+            return true;
+        }
+    }
+
+    static class LoadSmallScaledBitmapOp extends Op {
+        Context mContext;
+
+        LoadSmallScaledBitmapOp() {
+            super("LoadSmallScaledBitmap", "Load small raw bitmap that is scaled for density");
+        }
+
+        void onInit(Context context) {
+            mContext = context;
+        }
+
+        boolean onRun() {
+            BitmapFactory.Options opts = new BitmapFactory.Options();
+            opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
+            Bitmap bm = BitmapFactory.decodeResource(mContext.getResources(),
+                    R.drawable.stat_sample_scale, opts);
+            bm.recycle();
+            return true;
+        }
+    }
+
+    static class LoadLargeScaledBitmapOp extends Op {
+        Context mContext;
+
+        LoadLargeScaledBitmapOp() {
+            super("LoadLargeScaledBitmap", "Load large raw bitmap that is scaled for density");
+        }
+
+        void onInit(Context context) {
+            mContext = context;
+        }
+
+        boolean onRun() {
+            BitmapFactory.Options opts = new BitmapFactory.Options();
+            opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
+            Bitmap bm = BitmapFactory.decodeResource(mContext.getResources(),
+                    R.drawable.wallpaper_goldengate_scale, opts);
+            bm.recycle();
+            return true;
+        }
+    }
+}
diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java b/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
new file mode 100644
index 0000000..7691e64
--- /dev/null
+++ b/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworkperf;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class SchedulerService extends Service {
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Notification status = new Notification(R.drawable.stat_happy, null,
+                System.currentTimeMillis());
+        status.flags |= Notification.FLAG_ONGOING_EVENT;
+        status.setLatestEventInfo(this, "Scheduler Test running",
+                "Scheduler Test running", PendingIntent.getActivity(this, 0,
+                    new Intent(this, FrameworkPerfActivity.class)
+                    .setAction(Intent.ACTION_MAIN)
+                    .addCategory(Intent.CATEGORY_LAUNCHER)
+                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0));
+        startForeground(1, status);
+        return START_STICKY;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}
diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/SimpleInflater.java b/tests/FrameworkPerf/src/com/android/frameworkperf/SimpleInflater.java
new file mode 100644
index 0000000..5cbb12a
--- /dev/null
+++ b/tests/FrameworkPerf/src/com/android/frameworkperf/SimpleInflater.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworkperf;
+
+import java.io.IOException;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.util.AttributeSet;
+import android.util.Xml;
+import android.view.InflateException;
+
+public class SimpleInflater {
+    /** Menu tag name in XML. */
+    private static final String XML_MENU = "menu";
+    
+    /** Group tag name in XML. */
+    private static final String XML_GROUP = "group";
+    
+    /** Item tag name in XML. */
+    private static final String XML_ITEM = "item";
+
+    private Context mContext;
+
+    public SimpleInflater(Context context) {
+        mContext = context;
+    }
+
+    public void inflate(int menuRes) {
+        XmlResourceParser parser = null;
+        try {
+            parser = mContext.getResources().getLayout(menuRes);
+            AttributeSet attrs = Xml.asAttributeSet(parser);
+            
+            parseMenu(parser, attrs);
+        } catch (XmlPullParserException e) {
+            throw new InflateException("Error inflating menu XML", e);
+        } catch (IOException e) {
+            throw new InflateException("Error inflating menu XML", e);
+        } finally {
+            if (parser != null) parser.close();
+        }
+    }
+
+    private void parseMenu(XmlPullParser parser, AttributeSet attrs)
+            throws XmlPullParserException, IOException {
+        int eventType = parser.getEventType();
+        String tagName;
+        boolean lookingForEndOfUnknownTag = false;
+        String unknownTagName = null;
+
+        // This loop will skip to the menu start tag
+        do {
+            if (eventType == XmlPullParser.START_TAG) {
+                tagName = parser.getName();
+                if (tagName.equals(XML_MENU)) {
+                    // Go to next tag
+                    eventType = parser.next();
+                    break;
+                }
+                
+                throw new RuntimeException("Expecting menu, got " + tagName);
+            }
+            eventType = parser.next();
+        } while (eventType != XmlPullParser.END_DOCUMENT);
+        
+        boolean reachedEndOfMenu = false;
+        while (!reachedEndOfMenu) {
+            switch (eventType) {
+                case XmlPullParser.START_TAG:
+                    if (lookingForEndOfUnknownTag) {
+                        break;
+                    }
+                    
+                    tagName = parser.getName();
+                    if (tagName.equals(XML_ITEM)) {
+                        readItem(attrs);
+                    } else if (tagName.equals(XML_MENU)) {
+                        parseMenu(parser, attrs);
+                    } else {
+                        lookingForEndOfUnknownTag = true;
+                        unknownTagName = tagName;
+                    }
+                    break;
+                    
+                case XmlPullParser.END_TAG:
+                    tagName = parser.getName();
+                    if (lookingForEndOfUnknownTag && tagName.equals(unknownTagName)) {
+                        lookingForEndOfUnknownTag = false;
+                        unknownTagName = null;
+                    } else if (tagName.equals(XML_ITEM)) {
+                    } else if (tagName.equals(XML_MENU)) {
+                        reachedEndOfMenu = true;
+                    }
+                    break;
+                    
+                case XmlPullParser.END_DOCUMENT:
+                    throw new RuntimeException("Unexpected end of document");
+            }
+            
+            eventType = parser.next();
+        }
+    }
+
+    public void readItem(AttributeSet attrs) {
+        TypedArray a = mContext.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.MenuItem);
+
+        // Inherit attributes from the group as default value
+        int itemId = a.getResourceId(R.styleable.MenuItem_android_id, 0);
+        final int category = a.getInt(R.styleable.MenuItem_android_menuCategory, 0);
+        final int order = a.getInt(R.styleable.MenuItem_android_orderInCategory, 0);
+        CharSequence itemTitle = a.getText(R.styleable.MenuItem_android_title);
+        CharSequence itemTitleCondensed = a.getText(R.styleable.MenuItem_android_titleCondensed);
+        int itemIconResId = a.getResourceId(R.styleable.MenuItem_android_icon, 0);
+        String itemAlphabeticShortcut = a.getString(R.styleable.MenuItem_android_alphabeticShortcut);
+        String itemNumericShortcut = a.getString(R.styleable.MenuItem_android_numericShortcut);
+        int itemCheckable = 0;
+        if (a.hasValue(R.styleable.MenuItem_android_checkable)) {
+            // Item has attribute checkable, use it
+            itemCheckable = a.getBoolean(R.styleable.MenuItem_android_checkable, false) ? 1 : 0;
+        }
+        boolean itemChecked = a.getBoolean(R.styleable.MenuItem_android_checked, false);
+        boolean itemVisible = a.getBoolean(R.styleable.MenuItem_android_visible, false);
+        boolean itemEnabled = a.getBoolean(R.styleable.MenuItem_android_enabled, false);
+
+        a.recycle();
+    }
+}