Merge "Add a new state machine for handling the incoming / outgoing profile connections." into kraken
diff --git a/Android.mk b/Android.mk
index 5c95d20..3041065 100644
--- a/Android.mk
+++ b/Android.mk
@@ -86,7 +86,6 @@
 	core/java/android/app/ISearchManager.aidl \
 	core/java/android/app/ISearchManagerCallback.aidl \
 	core/java/android/app/IServiceConnection.aidl \
-	core/java/android/app/IStatusBar.aidl \
 	core/java/android/app/IThumbnailReceiver.aidl \
 	core/java/android/app/ITransientNotification.aidl \
 	core/java/android/app/IUiModeManager.aidl \
@@ -155,6 +154,8 @@
 	core/java/com/android/internal/backup/IBackupTransport.aidl \
 	core/java/com/android/internal/os/IDropBoxManagerService.aidl \
 	core/java/com/android/internal/os/IResultReceiver.aidl \
+	core/java/com/android/internal/statusbar/IStatusBar.aidl \
+	core/java/com/android/internal/statusbar/IStatusBarService.aidl \
 	core/java/com/android/internal/view/IInputContext.aidl \
 	core/java/com/android/internal/view/IInputContextCallback.aidl \
 	core/java/com/android/internal/view/IInputMethod.aidl \
@@ -403,6 +404,8 @@
                             resources/samples/CubeLiveWallpaper "Live Wallpaper" \
 		-samplecode $(sample_dir)/Home \
 		            resources/samples/Home "Home" \
+		-samplecode $(sample_dir)/HeavyWeight \
+		            resources/samples/HeavyWeight "Heavy Weight App" \
 		-samplecode $(sample_dir)/JetBoy \
 		            resources/samples/JetBoy "JetBoy" \
 		-samplecode $(sample_dir)/LunarLander \
@@ -411,8 +414,8 @@
 		            resources/samples/MultiResolution "Multiple Resolutions" \
 		-samplecode $(sample_dir)/NotePad \
 		            resources/samples/NotePad "Note Pad" \
-                -samplecode $(sample_dir)/SampleSyncAdapter \
-                            resources/samples/SampleSyncAdapter "Sample Sync Adapter" \
+		-samplecode $(sample_dir)/SampleSyncAdapter \
+		            resources/samples/SampleSyncAdapter "Sample Sync Adapter" \
 		-samplecode $(sample_dir)/SearchableDictionary \
 		            resources/samples/SearchableDictionary "Searchable Dictionary v2" \
 		-samplecode $(sample_dir)/Snake \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 6455103..26d8a1b 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -53,6 +53,7 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/FrameworkTest_intermediates/)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android.policy*)
 $(call add-clean-step, rm -rf $(TARGET_OUT_JAVA_LIBRARIES)/android.policy.jar)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
 
 
 # ************************************************
diff --git a/api/current.xml b/api/current.xml
index e6780be..d002534 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -4508,6 +4508,17 @@
  visibility="public"
 >
 </field>
+<field name="heavyWeight"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843456"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="height"
  type="int"
  transient="false"
@@ -5916,17 +5927,6 @@
  visibility="public"
 >
 </field>
-<field name="kraken_resource_pad65"
- type="int"
- transient="false"
- volatile="false"
- value="16843456"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="kraken_resource_pad7"
  type="int"
  transient="false"
@@ -21759,6 +21759,17 @@
  visibility="public"
 >
 </field>
+<field name="IMPORTANCE_HEAVY_WEIGHT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="150"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="IMPORTANCE_SERVICE"
  type="int"
  transient="false"
@@ -26393,6 +26404,17 @@
 <parameter name="parcel" type="android.os.Parcel">
 </parameter>
 </constructor>
+<method name="clone"
+ return="android.app.Notification"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="describeContents"
  return="int"
  abstract="false"
@@ -44092,6 +44114,17 @@
  visibility="public"
 >
 </method>
+<method name="getTargetPackage"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="readIntentSenderOrNullFromParcel"
  return="android.content.IntentSender"
  abstract="false"
@@ -46286,6 +46319,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_HEAVY_WEIGHT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1048576"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_KILL_AFTER_RESTORE"
  type="int"
  transient="false"
@@ -138860,6 +138904,17 @@
  visibility="public"
 >
 </field>
+<field name="ACTION_APPLICATION_DETAILS_SETTINGS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.settings.APPLICATION_DETAILS_SETTINGS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ACTION_APPLICATION_DEVELOPMENT_SETTINGS"
  type="java.lang.String"
  transient="false"
@@ -211346,6 +211401,17 @@
 <parameter name="parent" type="android.view.ViewGroup">
 </parameter>
 </method>
+<method name="clone"
+ return="android.widget.RemoteViews"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="describeContents"
  return="int"
  abstract="false"
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index c9096cf..793b9d2 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -726,6 +726,12 @@
         public static final int IMPORTANCE_FOREGROUND = 100;
         
         /**
+         * Constant for {@link #importance}: this process is running a
+         * heavy-weight application and thus should not be killed.
+         */
+        public static final int IMPORTANCE_HEAVY_WEIGHT = 150;
+        
+        /**
          * Constant for {@link #importance}: this process is running something
          * that is considered to be actively visible to the user.
          */
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index f694285..b78d22f 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1251,6 +1251,13 @@
             reply.writeNoException();
             return true;
         }
+        
+        case FINISH_HEAVY_WEIGHT_APP_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            finishHeavyWeightApp();
+            reply.writeNoException();
+            return true;
+        }
         }
         
         return super.onTransact(code, data, reply, flags);
@@ -2758,5 +2765,15 @@
         return res;
     }
     
+    public void finishHeavyWeightApp() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(FINISH_HEAVY_WEIGHT_APP_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+    
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 31f0a63..cd24fa6 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -303,6 +303,8 @@
     
     public boolean isUserAMonkey() throws RemoteException;
     
+    public void finishHeavyWeightApp() throws RemoteException;
+    
     /*
      * Private non-Binder interfaces
      */
@@ -513,4 +515,5 @@
     int WILL_ACTIVITY_BE_VISIBLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+105;
     int START_ACTIVITY_WITH_CONFIG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+106;
     int GET_RUNNING_EXTERNAL_APPLICATIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+107;
+    int FINISH_HEAVY_WEIGHT_APP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+108;
 }
diff --git a/core/java/android/app/IStatusBar.aidl b/core/java/android/app/IStatusBar.aidl
deleted file mode 100644
index c64fa50..0000000
--- a/core/java/android/app/IStatusBar.aidl
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Copyright (c) 2007, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); 
- * you may not use this file except in compliance with the License. 
- * You may obtain a copy of the License at 
- *
- *     http://www.apache.org/licenses/LICENSE-2.0 
- *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
- * limitations under the License.
- */
- 
-package android.app;
-
-/** @hide */
-interface IStatusBar
-{
-    void activate();
-    void deactivate();
-    void toggle();
-    void disable(int what, IBinder token, String pkg);
-    IBinder addIcon(String slot, String iconPackage, int iconId, int iconLevel);
-    void updateIcon(IBinder key, String slot, String iconPackage, int iconId, int iconLevel);
-    void removeIcon(IBinder key);
-}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 4d72f73..739aca3 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -341,6 +341,44 @@
         iconLevel = parcel.readInt();
     }
 
+    public Notification clone() {
+        Notification that = new Notification();
+
+        that.when = this.when;
+        that.icon = this.icon;
+        that.number = this.number;
+
+        // PendingIntents are global, so there's no reason (or way) to clone them.
+        that.contentIntent = this.contentIntent;
+        that.deleteIntent = this.deleteIntent;
+
+        if (this.tickerText != null) {
+            that.tickerText = this.tickerText.toString();
+        }
+        if (this.contentView != null) {
+            that.contentView = this.contentView.clone();
+        }
+        that.iconLevel = that.iconLevel;
+        that.sound = this.sound; // android.net.Uri is immutable
+        that.audioStreamType = this.audioStreamType;
+
+        final long[] vibrate = this.vibrate;
+        if (vibrate != null) {
+            final int N = vibrate.length;
+            final long[] vib = that.vibrate = new long[N];
+            System.arraycopy(vibrate, 0, vib, 0, N);
+        }
+
+        that.ledARGB = this.ledARGB;
+        that.ledOnMS = this.ledOnMS;
+        that.ledOffMS = this.ledOffMS;
+        that.defaults = this.defaults;
+        
+        that.flags = this.flags;
+
+        return that;
+    }
+
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 72ec616..de544fb 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -23,6 +23,8 @@
 import android.os.IBinder;
 import android.os.ServiceManager;
 
+import com.android.internal.statusbar.IStatusBarService;
+
 /**
  * Allows an app to control the status bar.
  *
@@ -58,12 +60,12 @@
     public static final int DISABLE_NONE = 0x00000000;
 
     private Context mContext;
-    private IStatusBar mService;
+    private IStatusBarService mService;
     private IBinder mToken = new Binder();
 
     StatusBarManager(Context context) {
         mContext = context;
-        mService = IStatusBar.Stub.asInterface(
+        mService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
     }
 
@@ -85,7 +87,7 @@
      */
     public void expand() {
         try {
-            mService.activate();
+            mService.expand();
         } catch (RemoteException ex) {
             // system process is dead anyway.
             throw new RuntimeException(ex);
@@ -97,46 +99,34 @@
      */
     public void collapse() {
         try {
-            mService.deactivate();
-        } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
-        }
-    }
-    
-    /**
-     * Toggle the status bar.
-     */
-    public void toggle() {
-        try {
-            mService.toggle();
+            mService.collapse();
         } catch (RemoteException ex) {
             // system process is dead anyway.
             throw new RuntimeException(ex);
         }
     }
 
-    public IBinder addIcon(String slot, int iconId, int iconLevel) {
+    public void setIcon(String slot, int iconId, int iconLevel) {
         try {
-            return mService.addIcon(slot, mContext.getPackageName(), iconId, iconLevel);
+            mService.setIcon(slot, mContext.getPackageName(), iconId, iconLevel);
         } catch (RemoteException ex) {
             // system process is dead anyway.
             throw new RuntimeException(ex);
         }
     }
 
-    public void updateIcon(IBinder key, String slot, int iconId, int iconLevel) {
+    public void removeIcon(String slot) {
         try {
-            mService.updateIcon(key, slot, mContext.getPackageName(), iconId, iconLevel);
+            mService.removeIcon(slot);
         } catch (RemoteException ex) {
             // system process is dead anyway.
             throw new RuntimeException(ex);
         }
     }
 
-    public void removeIcon(IBinder key) {
+    public void setIconVisibility(String slot, boolean visible) {
         try {
-            mService.removeIcon(key);
+            mService.setIconVisibility(slot, visible);
         } catch (RemoteException ex) {
             // system process is dead anyway.
             throw new RuntimeException(ex);
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index e182021..007a715 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.app.ActivityManagerNative;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IIntentSender;
@@ -170,6 +171,25 @@
     }
 
     /**
+     * Return the package name of the application that created this
+     * IntentSender, that is the identity under which you will actually be
+     * sending the Intent.  The returned string is supplied by the system, so
+     * that an application can not spoof its package.
+     *
+     * @return The package name of the PendingIntent, or null if there is
+     * none associated with it.
+     */
+    public String getTargetPackage() {
+        try {
+            return ActivityManagerNative.getDefault()
+                .getPackageForIntentSender(mTarget);
+        } catch (RemoteException e) {
+            // Should never happen.
+            return null;
+        }
+    }
+
+    /**
      * Comparison operator on two IntentSender objects, such that true
      * is returned then they both represent the same operation from the
      * same package.
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 7047113..7901b155 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -273,6 +273,17 @@
     public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 1<<19;
     
     /**
+     * Value for {@link #flags}: set to <code>true</code> if the application
+     * has reported that it is heavy-weight, and thus can not participate in
+     * the normal application lifecycle.
+     * 
+     * <p>Comes from the
+     * {@link android.R.styleable#AndroidManifestApplication_heavyWeight android:heavyWeight}
+     * attribute of the &lt;application&gt; tag.
+     */
+    public static final int FLAG_HEAVY_WEIGHT = 1<<20;
+    
+    /**
      * Value for {@link #flags}: this is true if the application has set
      * its android:neverEncrypt to true, false otherwise. It is used to specify
      * that this package specifically "opts-out" of a secured file system solution,
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 4ddc124..a5f5acc 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1600,6 +1600,18 @@
     
             ai.enabled = sa.getBoolean(
                     com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);
+            
+            if (sa.getBoolean(
+                    com.android.internal.R.styleable.AndroidManifestApplication_heavyWeight,
+                    false)) {
+                ai.flags |= ApplicationInfo.FLAG_HEAVY_WEIGHT;
+                
+                // A heavy-weight application can not be in a custom process.
+                // We can do direct compare because we intern all strings.
+                if (ai.processName != null && ai.processName != ai.packageName) {
+                    outError[0] = "Heavy-weight applications can not use custom processes";
+                }
+            }
         }
 
         sa.recycle();
@@ -1889,6 +1901,14 @@
 
         sa.recycle();
 
+        if (receiver && (owner.applicationInfo.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) {
+            // A heavy-weight application can not have receives in its main process
+            // We can do direct compare because we intern all strings.
+            if (a.info.processName == owner.packageName) {
+                outError[0] = "Heavy-weight applications can not have receivers in main process";
+            }
+        }
+        
         if (outError[0] != null) {
             return null;
         }
@@ -2171,6 +2191,15 @@
 
         sa.recycle();
 
+        if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) {
+            // A heavy-weight application can not have providers in its main process
+            // We can do direct compare because we intern all strings.
+            if (p.info.processName == owner.packageName) {
+                outError[0] = "Heavy-weight applications can not have providers in main process";
+                return null;
+            }
+        }
+        
         if (cpname == null) {
             outError[0] = "<provider> does not incude authorities attribute";
             return null;
@@ -2403,6 +2432,15 @@
 
         sa.recycle();
 
+        if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) {
+            // A heavy-weight application can not have services in its main process
+            // We can do direct compare because we intern all strings.
+            if (s.info.processName == owner.packageName) {
+                outError[0] = "Heavy-weight applications can not have services in main process";
+                return null;
+            }
+        }
+        
         int outerDepth = parser.getDepth();
         int type;
         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index d4f9b20..0e798dc 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -33,6 +33,8 @@
 import android.util.Log;
 import android.util.Pair;
 
+import dalvik.system.BlockGuard;
+
 import java.io.File;
 import java.lang.ref.WeakReference;
 import java.text.SimpleDateFormat;
@@ -1339,6 +1341,7 @@
         if (!isOpen()) {
             throw new IllegalStateException("database not open");
         }
+        BlockGuard.getThreadPolicy().onReadFromDisk();
         long timeStart = 0;
 
         if (Config.LOGV || mSlowQueryThreshold != -1) {
@@ -1497,6 +1500,7 @@
      */
     public long insertWithOnConflict(String table, String nullColumnHack,
             ContentValues initialValues, int conflictAlgorithm) {
+        BlockGuard.getThreadPolicy().onWriteToDisk();
         if (!isOpen()) {
             throw new IllegalStateException("database not open");
         }
@@ -1588,6 +1592,7 @@
      *         whereClause.
      */
     public int delete(String table, String whereClause, String[] whereArgs) {
+        BlockGuard.getThreadPolicy().onWriteToDisk();
         lock();
         if (!isOpen()) {
             throw new IllegalStateException("database not open");
@@ -1643,6 +1648,7 @@
      */
     public int updateWithOnConflict(String table, ContentValues values,
             String whereClause, String[] whereArgs, int conflictAlgorithm) {
+        BlockGuard.getThreadPolicy().onWriteToDisk();
         if (values == null || values.size() == 0) {
             throw new IllegalArgumentException("Empty values");
         }
@@ -1725,6 +1731,7 @@
      * @throws SQLException If the SQL string is invalid for some reason
      */
     public void execSQL(String sql) throws SQLException {
+        BlockGuard.getThreadPolicy().onWriteToDisk();
         long timeStart = SystemClock.uptimeMillis();
         lock();
         if (!isOpen()) {
@@ -1760,6 +1767,7 @@
      * @throws SQLException If the SQL string is invalid for some reason
      */
     public void execSQL(String sql, Object[] bindArgs) throws SQLException {
+        BlockGuard.getThreadPolicy().onWriteToDisk();
         if (bindArgs == null) {
             throw new IllegalArgumentException("Empty bindArgs");
         }
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index 47cca87..9e425c3 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -18,6 +18,8 @@
 
 import android.os.SystemClock;
 
+import dalvik.system.BlockGuard;
+
 /**
  * A pre-compiled statement against a {@link SQLiteDatabase} that can be reused.
  * The statement cannot return multiple rows, but 1x1 result sets are allowed.
@@ -47,6 +49,7 @@
      *         some reason
      */
     public void execute() {
+        BlockGuard.getThreadPolicy().onWriteToDisk();
         if (!mDatabase.isOpen()) {
             throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
         }
@@ -73,6 +76,7 @@
      *         some reason
      */
     public long executeInsert() {
+        BlockGuard.getThreadPolicy().onWriteToDisk();
         if (!mDatabase.isOpen()) {
             throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
         }
@@ -99,6 +103,7 @@
      * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
      */
     public long simpleQueryForLong() {
+        BlockGuard.getThreadPolicy().onReadFromDisk();
         if (!mDatabase.isOpen()) {
             throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
         }
@@ -125,6 +130,7 @@
      * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
      */
     public String simpleQueryForString() {
+        BlockGuard.getThreadPolicy().onReadFromDisk();
         if (!mDatabase.isOpen()) {
             throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
         }
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 54aa363..025db4a 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -763,6 +763,7 @@
         private static final String KEY_ZOOM_SUPPORTED = "zoom-supported";
         private static final String KEY_SMOOTH_ZOOM_SUPPORTED = "smooth-zoom-supported";
         private static final String KEY_FOCUS_DISTANCES = "focus-distances";
+        private static final String KEY_METERING_MODE = "metering-mode";
 
         // Parameter key suffix for supported values.
         private static final String SUPPORTED_VALUES_SUFFIX = "-values";
@@ -965,6 +966,26 @@
          */
         public static final String FOCUS_MODE_CONTINUOUS = "continuous";
 
+        /**
+         * The camera determines the exposure by giving more weight to the
+         * central part of the scene.
+         * @hide
+         */
+        public static final String METERING_MODE_CENTER_WEIGHTED = "center-weighted";
+
+        /**
+         * The camera determines the exposure by averaging the entire scene,
+         * giving no weighting to any particular area.
+         * @hide
+         */
+        public static final String METERING_MODE_FRAME_AVERAGE = "frame-average";
+
+        /**
+         * The camera determines the exposure by a very small area of the scene,
+         * typically the center.
+         * @hide
+         */
+        public static final String METERING_MODE_SPOT = "spot";
 
         // Formats for setPreviewFormat and setPictureFormat.
         private static final String PIXEL_FORMAT_YUV422SP = "yuv422sp";
@@ -1930,6 +1951,45 @@
             output[2] = distances.get(2);
         }
 
+        /**
+         * Gets the supported metering modes.
+         *
+         * @return a list of supported metering modes. null if metering mode
+         *         setting is not supported.
+         * @see #getMeteringMode()
+         * @hide
+         */
+        public List<String> getSupportedMeteringModes() {
+            String str = get(KEY_METERING_MODE + SUPPORTED_VALUES_SUFFIX);
+            return split(str);
+        }
+
+        /**
+         * Gets the current metering mode, which affects how camera determines
+         * exposure.
+         *
+         * @return current metering mode. If the camera does not support
+         *         metering setting, this should return null.
+         * @see #METERING_MODE_CENTER_WEIGHTED
+         * @see #METERING_MODE_FRAME_AVERAGE
+         * @see #METERING_MODE_SPOT
+         * @hide
+         */
+        public String getMeteringMode() {
+            return get(KEY_METERING_MODE);
+        }
+
+        /**
+         * Sets the metering mode.
+         *
+         * @param value metering mode.
+         * @see #getMeteringMode()
+         * @hide
+         */
+        public void setMeteringMode(String value) {
+            set(KEY_METERING_MODE, value);
+        }
+
         // Splits a comma delimited string to an ArrayList of String.
         // Return null if the passing string is null or the size is 0.
         private ArrayList<String> split(String str) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9f19f11..7bb89f5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -355,6 +355,21 @@
             "android.settings.MANAGE_APPLICATIONS_SETTINGS";
 
     /**
+     * Activity Action: Show screen of details about a particular application.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: The Intent's data URI specifies the application package name
+     * to be shown, with the "package" scheme.  That is "package:com.my.app".
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_APPLICATION_DETAILS_SETTINGS =
+            "android.settings.APPLICATION_DETAILS_SETTINGS";
+
+    /**
      * Activity Action: Show settings for system update functionality.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -2368,6 +2383,24 @@
         public static final String TETHER_SUPPORTED = "tether_supported";
 
         /**
+         * Used to require DUN APN on the device or not - defaults to a build config value
+         * which defaults to false
+         * @hide
+         */
+        public static final String TETHER_DUN_REQUIRED = "tether_dun_required";
+
+        /**
+         * Used to hold a gservices-provisioned apn value for DUN.  If set, or the
+         * corresponding build config values are set it will override the APN DB
+         * values.
+         * Consists of a comma seperated list 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"
+         * @hide
+         */
+        public static final String TETHER_DUN_APN = "tether_dun_apn";
+
+        /**
          * No longer supported.
          */
         public static final String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
diff --git a/core/java/android/text/util/Rfc822Tokenizer.java b/core/java/android/text/util/Rfc822Tokenizer.java
index 952d833..69cf93c 100644
--- a/core/java/android/text/util/Rfc822Tokenizer.java
+++ b/core/java/android/text/util/Rfc822Tokenizer.java
@@ -84,8 +84,10 @@
                     if (c == '"') {
                         i++;
                         break;
-                    } else if (c == '\\' && i + 1 < cursor) {
-                        name.append(text.charAt(i + 1));
+                    } else if (c == '\\') {
+                        if (i + 1 < cursor) {
+                            name.append(text.charAt(i + 1));
+                        }
                         i += 2;
                     } else {
                         name.append(c);
@@ -110,8 +112,10 @@
                         comment.append(c);
                         level++;
                         i++;
-                    } else if (c == '\\' && i + 1 < cursor) {
-                        comment.append(text.charAt(i + 1));
+                    } else if (c == '\\') {
+                        if (i + 1 < cursor) {
+                            comment.append(text.charAt(i + 1));
+                        }
                         i += 2;
                     } else {
                         comment.append(c);
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index d648e96..eefbf7a 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -255,17 +255,19 @@
     }
 
     static private MotionEvent obtain() {
+        final MotionEvent ev;
         synchronized (gRecyclerLock) {
             if (gRecyclerTop == null) {
                 return new MotionEvent();
             }
-            MotionEvent ev = gRecyclerTop;
+            ev = gRecyclerTop;
             gRecyclerTop = ev.mNext;
             gRecyclerUsed--;
-            ev.mRecycledLocation = null;
-            ev.mRecycled = false;
-            return ev;
         }
+        ev.mRecycledLocation = null;
+        ev.mRecycled = false;
+        ev.mNext = null;
+        return ev;
     }
 
     /**
@@ -620,11 +622,14 @@
                 throw new RuntimeException(toString() + " recycled twice!", mRecycledLocation);
             }
             mRecycledLocation = new RuntimeException("Last recycled here");
-        } else if (mRecycled) {
-            throw new RuntimeException(toString() + " recycled twice!");
+            //Log.w("MotionEvent", "Recycling event " + this, mRecycledLocation);
+        } else {
+            if (mRecycled) {
+                throw new RuntimeException(toString() + " recycled twice!");
+            }
+            mRecycled = true;
         }
 
-        //Log.w("MotionEvent", "Recycling event " + this, mRecycledLocation);
         synchronized (gRecyclerLock) {
             if (gRecyclerUsed < MAX_RECYCLED) {
                 gRecyclerUsed++;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 921d0f5..ac23832 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1380,16 +1380,23 @@
         final File temp = new File(dest.getPath() + ".writing");
         new Thread(new Runnable() {
             public void run() {
+                FileOutputStream out = null;
                 try {
-                    FileOutputStream out = new FileOutputStream(temp);
+                    out = new FileOutputStream(temp);
                     p.writeToStream(out);
-                    out.close();
                     // Writing the picture succeeded, rename the temporary file
                     // to the destination.
                     temp.renameTo(dest);
                 } catch (Exception e) {
                     // too late to do anything about it.
                 } finally {
+                    if (out != null) {
+                        try {
+                            out.close();
+                        } catch (Exception e) {
+                            // Can't do anything about that
+                        }
+                    }
                     temp.delete();
                 }
             }
@@ -1442,20 +1449,23 @@
             final Bundle copy = new Bundle(b);
             new Thread(new Runnable() {
                 public void run() {
-                    final Picture p = Picture.createFromStream(in);
-                    if (p != null) {
-                        // Post a runnable on the main thread to update the
-                        // history picture fields.
-                        mPrivateHandler.post(new Runnable() {
-                            public void run() {
-                                restoreHistoryPictureFields(p, copy);
-                            }
-                        });
-                    }
                     try {
-                        in.close();
-                    } catch (Exception e) {
-                        // Nothing we can do now.
+                        final Picture p = Picture.createFromStream(in);
+                        if (p != null) {
+                            // Post a runnable on the main thread to update the
+                            // history picture fields.
+                            mPrivateHandler.post(new Runnable() {
+                                public void run() {
+                                    restoreHistoryPictureFields(p, copy);
+                                }
+                            });
+                        }
+                    } finally {
+                        try {
+                            in.close();
+                        } catch (Exception e) {
+                            // Nothing we can do now.
+                        }
                     }
                 }
             }).start();
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 3003580..7a70c80 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -100,6 +100,7 @@
      * Base class for all actions that can be performed on an 
      * inflated view.
      *
+     *  SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!!
      */
     private abstract static class Action implements Parcelable {
         public abstract void apply(View root) throws ActionException;
@@ -568,6 +569,14 @@
         }
     }
 
+    public RemoteViews clone() {
+        final RemoteViews that = new RemoteViews(mPackage, mLayoutId);
+        if (mActions != null) {
+            that.mActions = (ArrayList<Action>)mActions.clone();
+        }
+        return that;
+    }
+
     public String getPackage() {
         return mPackage;
     }
diff --git a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
new file mode 100644
index 0000000..ada7f36
--- /dev/null
+++ b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.app;
+
+import com.android.internal.R;
+
+import android.app.Activity;
+import android.app.ActivityManagerNative;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.View;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * This activity is displayed when the system attempts to start an Intent for
+ * which there is more than one matching activity, allowing the user to decide
+ * which to go to.  It is not normally used directly by application developers.
+ */
+public class HeavyWeightSwitcherActivity extends Activity {
+    /** The PendingIntent of the new activity being launched. */
+    public static final String KEY_INTENT = "intent";
+    /** Set if the caller is requesting a result. */
+    public static final String KEY_HAS_RESULT = "has_result";
+    /** Package of current heavy-weight app. */
+    public static final String KEY_CUR_APP = "cur_app";
+    /** Task that current heavy-weight activity is running in. */
+    public static final String KEY_CUR_TASK = "cur_task";
+    /** Package of newly requested heavy-weight app. */
+    public static final String KEY_NEW_APP = "new_app";
+    
+    IntentSender mStartIntent;
+    boolean mHasResult;
+    String mCurApp;
+    int mCurTask;
+    String mNewApp;
+    
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        requestWindowFeature(Window.FEATURE_LEFT_ICON);
+        
+        mStartIntent = (IntentSender)getIntent().getParcelableExtra(KEY_INTENT);
+        mHasResult = getIntent().getBooleanExtra(KEY_HAS_RESULT, false);
+        mCurApp = getIntent().getStringExtra(KEY_CUR_APP);
+        mCurTask = getIntent().getIntExtra(KEY_CUR_TASK, 0);
+        mNewApp = getIntent().getStringExtra(KEY_NEW_APP);
+        
+        setContentView(com.android.internal.R.layout.heavy_weight_switcher);
+        
+        setIconAndText(R.id.old_app_icon, R.id.old_app_action, R.id.old_app_description,
+                mCurApp, R.string.old_app_action, R.string.old_app_description);
+        setIconAndText(R.id.new_app_icon, R.id.new_app_action, R.id.new_app_description,
+                mNewApp, R.string.new_app_action, R.string.new_app_description);
+            
+        View button = findViewById((R.id.switch_old));
+        button.setOnClickListener(mSwitchOldListener);
+        button = findViewById((R.id.switch_new));
+        button.setOnClickListener(mSwitchNewListener);
+        button = findViewById((R.id.cancel));
+        button.setOnClickListener(mCancelListener);
+        
+        getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, 
+                android.R.drawable.ic_dialog_alert);
+    }
+
+    void setText(int id, CharSequence text) {
+        ((TextView)findViewById(id)).setText(text);
+    }
+    
+    void setDrawable(int id, Drawable dr) {
+        if (dr != null) {
+            ((ImageView)findViewById(id)).setImageDrawable(dr);
+        }
+    }
+    
+    void setIconAndText(int iconId, int actionId, int descriptionId,
+            String packageName, int actionStr, int descriptionStr) {
+        CharSequence appName = "";
+        Drawable appIcon = null;
+        if (mCurApp != null) {
+            try {
+                ApplicationInfo info = getPackageManager().getApplicationInfo(
+                        packageName, 0);
+                appName = info.loadLabel(getPackageManager());
+                appIcon = info.loadIcon(getPackageManager());
+            } catch (PackageManager.NameNotFoundException e) {
+            }
+        }
+        
+        setDrawable(iconId, appIcon);
+        setText(actionId, getString(actionStr, appName));
+        setText(descriptionId, getText(descriptionStr));
+    }
+    
+    private OnClickListener mSwitchOldListener = new OnClickListener() {
+        public void onClick(View v) {
+            try {
+                ActivityManagerNative.getDefault().moveTaskToFront(mCurTask);
+            } catch (RemoteException e) {
+            }
+            finish();
+        }
+    };
+    
+    private OnClickListener mSwitchNewListener = new OnClickListener() {
+        public void onClick(View v) {
+            try {
+                ActivityManagerNative.getDefault().finishHeavyWeightApp();
+            } catch (RemoteException e) {
+            }
+            try {
+                if (mHasResult) {
+                    startIntentSenderForResult(mStartIntent, -1, null,
+                            Intent.FLAG_ACTIVITY_FORWARD_RESULT,
+                            Intent.FLAG_ACTIVITY_FORWARD_RESULT, 0);
+                } else {
+                    startIntentSenderForResult(mStartIntent, -1, null, 0, 0, 0);
+                }
+            } catch (IntentSender.SendIntentException ex) {
+                Log.w("HeavyWeightSwitcherActivity", "Failure starting", ex);
+            }
+            finish();
+        }
+    };
+    
+    private OnClickListener mCancelListener = new OnClickListener() {
+        public void onClick(View v) {
+            finish();
+        }
+    };
+}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
new file mode 100644
index 0000000..4501bd7
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+ 
+package com.android.internal.statusbar;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarNotification;
+
+/** @hide */
+oneway interface IStatusBar
+{
+    void setIcon(int index, in StatusBarIcon icon);
+    void removeIcon(int index);
+    void addNotification(IBinder key, in StatusBarNotification notification);
+    void updateNotification(IBinder key, in StatusBarNotification notification);
+    void removeNotification(IBinder key);
+    void disable(int state);
+    void animateExpand();
+    void animateCollapse();
+}
+
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
new file mode 100644
index 0000000..1f25b37
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+ 
+package com.android.internal.statusbar;
+
+import com.android.internal.statusbar.IStatusBar;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.StatusBarNotification;
+
+/** @hide */
+interface IStatusBarService
+{
+    void expand();
+    void collapse();
+    void disable(int what, IBinder token, String pkg);
+    void setIcon(String slot, String iconPackage, int iconId, int iconLevel);
+    void setIconVisibility(String slot, boolean visible);
+    void removeIcon(String slot);
+
+    // ---- Methods below are for use by the status bar policy services ----
+    void registerStatusBar(IStatusBar callbacks, out StatusBarIconList iconList,
+            out List<IBinder> notificationKeys, out List<StatusBarNotification> notifications);
+    void visibilityChanged(boolean visible);
+    void onNotificationClick(String pkg, String tag, int id);
+    void onClearAllNotifications();
+}
diff --git a/core/java/com/android/internal/statusbar/StatusBarIcon.aidl b/core/java/com/android/internal/statusbar/StatusBarIcon.aidl
new file mode 100644
index 0000000..311a077
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/StatusBarIcon.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.statusbar;
+
+parcelable StatusBarIcon;
+
diff --git a/core/java/com/android/internal/statusbar/StatusBarIcon.java b/core/java/com/android/internal/statusbar/StatusBarIcon.java
new file mode 100644
index 0000000..ae2cac2
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/StatusBarIcon.java
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.statusbar;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+public class StatusBarIcon implements Parcelable {
+    public String iconPackage;
+    public int iconId;
+    public int iconLevel;
+    public boolean visible = true;
+    public int number;
+
+    private StatusBarIcon() {
+    }
+
+    public StatusBarIcon(String iconPackage, int iconId, int iconLevel) {
+        this.iconPackage = iconPackage;
+        this.iconId = iconId;
+        this.iconLevel = iconLevel;
+    }
+
+    public StatusBarIcon(String iconPackage, int iconId, int iconLevel, int number) {
+        this.iconPackage = iconPackage;
+        this.iconId = iconId;
+        this.iconLevel = iconLevel;
+        this.number = number;
+    }
+
+    public String toString() {
+        return "StatusBarIcon(pkg=" + this.iconPackage + " id=0x" + Integer.toHexString(this.iconId)
+                + " level=" + this.iconLevel + " visible=" + visible
+                + " num=" + this.number + " )";
+    }
+
+    public StatusBarIcon clone() {
+        StatusBarIcon that = new StatusBarIcon(this.iconPackage, this.iconId, this.iconLevel);
+        that.visible = this.visible;
+        that.number = this.number;
+        return that;
+    }
+
+    /**
+     * Unflatten the StatusBarIcon from a parcel.
+     */
+    public StatusBarIcon(Parcel in) {
+        readFromParcel(in);
+    }
+
+    public void readFromParcel(Parcel in) {
+        this.iconPackage = in.readString();
+        this.iconId = in.readInt();
+        this.iconLevel = in.readInt();
+        this.visible = in.readInt() != 0;
+        this.number = in.readInt();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(this.iconPackage);
+        out.writeInt(this.iconId);
+        out.writeInt(this.iconLevel);
+        out.writeInt(this.visible ? 1 : 0);
+        out.writeInt(this.number);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Parcelable.Creator that instantiates StatusBarIcon objects
+     */
+    public static final Parcelable.Creator<StatusBarIcon> CREATOR
+            = new Parcelable.Creator<StatusBarIcon>()
+    {
+        public StatusBarIcon createFromParcel(Parcel parcel)
+        {
+            return new StatusBarIcon(parcel);
+        }
+
+        public StatusBarIcon[] newArray(int size)
+        {
+            return new StatusBarIcon[size];
+        }
+    };
+}
+
diff --git a/core/java/com/android/internal/statusbar/StatusBarIconList.aidl b/core/java/com/android/internal/statusbar/StatusBarIconList.aidl
new file mode 100644
index 0000000..c745120
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/StatusBarIconList.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.statusbar;
+
+parcelable StatusBarIconList;
+
diff --git a/core/java/com/android/internal/statusbar/StatusBarIconList.java b/core/java/com/android/internal/statusbar/StatusBarIconList.java
new file mode 100644
index 0000000..478d245
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/StatusBarIconList.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.statusbar;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.PrintWriter;
+
+public class StatusBarIconList implements Parcelable {
+    private String[] mSlots;
+    private StatusBarIcon[] mIcons;
+
+    public StatusBarIconList() {
+    }
+
+    public StatusBarIconList(Parcel in) {
+        readFromParcel(in);
+    }
+    
+    public void readFromParcel(Parcel in) {
+        this.mSlots = in.readStringArray();
+        final int N = in.readInt();
+        if (N < 0) {
+            mIcons = null;
+        } else {
+            mIcons = new StatusBarIcon[N];
+            for (int i=0; i<N; i++) {
+                if (in.readInt() != 0) {
+                    mIcons[i] = new StatusBarIcon(in);
+                }
+            }
+        }
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeStringArray(mSlots);
+        if (mIcons == null) {
+            out.writeInt(-1);
+        } else {
+            final int N = mIcons.length;
+            out.writeInt(N);
+            for (int i=0; i<N; i++) {
+                StatusBarIcon ic = mIcons[i];
+                if (ic == null) {
+                    out.writeInt(0);
+                } else {
+                    out.writeInt(1);
+                    ic.writeToParcel(out, flags);
+                }
+            }
+        }
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Parcelable.Creator that instantiates StatusBarIconList objects
+     */
+    public static final Parcelable.Creator<StatusBarIconList> CREATOR
+            = new Parcelable.Creator<StatusBarIconList>()
+    {
+        public StatusBarIconList createFromParcel(Parcel parcel)
+        {
+            return new StatusBarIconList(parcel);
+        }
+
+        public StatusBarIconList[] newArray(int size)
+        {
+            return new StatusBarIconList[size];
+        }
+    };
+
+    public void defineSlots(String[] slots) {
+        final int N = slots.length;
+        String[] s = mSlots = new String[N];
+        for (int i=0; i<N; i++) {
+            s[i] = slots[i];
+        }
+        mIcons = new StatusBarIcon[N];
+    }
+
+    public int getSlotIndex(String slot) {
+        final int N = mSlots.length;
+        for (int i=0; i<N; i++) {
+            if (slot.equals(mSlots[i])) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    public int size() {
+        return mSlots.length;
+    }
+
+    public void setIcon(int index, StatusBarIcon icon) {
+        mIcons[index] = icon.clone();
+    }
+
+    public void removeIcon(int index) {
+        mIcons[index] = null;
+    }
+
+    public String getSlot(int index) {
+        return mSlots[index];
+    }
+
+    public StatusBarIcon getIcon(int index) {
+        return mIcons[index];
+    }
+
+    public int getViewIndex(int index) {
+        int count = 0;
+        for (int i=0; i<index; i++) {
+            if (mIcons[i] != null) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    public void copyFrom(StatusBarIconList that) {
+        if (that.mSlots == null) {
+            this.mSlots = null;
+            this.mIcons = null;
+        } else {
+            final int N = that.mSlots.length;
+            this.mSlots = new String[N];
+            this.mIcons = new StatusBarIcon[N];
+            for (int i=0; i<N; i++) {
+                this.mSlots[i] = that.mSlots[i];
+                this.mIcons[i] = that.mIcons[i] != null ? that.mIcons[i].clone() : null;
+            }
+        }
+    }
+
+    public void dump(PrintWriter pw) {
+        final int N = mSlots.length;
+        pw.println("Icon list:");
+        for (int i=0; i<N; i++) {
+            pw.printf("  %2d: (%s) %s\n", i, mSlots[i], mIcons[i]);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/statusbar/StatusBarNotification.aidl b/core/java/com/android/internal/statusbar/StatusBarNotification.aidl
new file mode 100644
index 0000000..bd9e89c
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/StatusBarNotification.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.statusbar;
+
+parcelable StatusBarNotification;
+
diff --git a/core/java/com/android/internal/statusbar/StatusBarNotification.java b/core/java/com/android/internal/statusbar/StatusBarNotification.java
new file mode 100644
index 0000000..5499676
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/StatusBarNotification.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.statusbar;
+
+import android.app.Notification;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.widget.RemoteViews;
+
+
+/*
+boolean clearable = !n.ongoingEvent && ((notification.flags & Notification.FLAG_NO_CLEAR) == 0);
+
+
+// TODO: make this restriction do something smarter like never fill
+// more than two screens.  "Why would anyone need more than 80 characters." :-/
+final int maxTickerLen = 80;
+if (truncatedTicker != null && truncatedTicker.length() > maxTickerLen) {
+    truncatedTicker = truncatedTicker.subSequence(0, maxTickerLen);
+}
+*/
+
+public class StatusBarNotification implements Parcelable {
+    public String pkg;
+    public int id;
+    public String tag;
+    public Notification notification;
+
+    public StatusBarNotification() {
+    }
+
+    public StatusBarNotification(String pkg, int id, String tag, Notification notification) {
+        if (pkg == null) throw new NullPointerException();
+        if (notification == null) throw new NullPointerException();
+
+        this.pkg = pkg;
+        this.id = id;
+        this.tag = tag;
+        this.notification = notification;
+    }
+
+    public StatusBarNotification(Parcel in) {
+        readFromParcel(in);
+    }
+
+    public void readFromParcel(Parcel in) {
+        this.pkg = in.readString();
+        this.id = in.readInt();
+        if (in.readInt() != 0) {
+            this.tag = in.readString();
+        } else {
+            this.tag = null;
+        }
+        this.notification = new Notification(in);
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(this.pkg);
+        out.writeInt(this.id);
+        if (this.tag != null) {
+            out.writeInt(1);
+            out.writeString(this.tag);
+        } else {
+            out.writeInt(0);
+        }
+        this.notification.writeToParcel(out, flags);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<StatusBarNotification> CREATOR
+            = new Parcelable.Creator<StatusBarNotification>()
+    {
+        public StatusBarNotification createFromParcel(Parcel parcel)
+        {
+            return new StatusBarNotification(parcel);
+        }
+
+        public StatusBarNotification[] newArray(int size)
+        {
+            return new StatusBarNotification[size];
+        }
+    };
+
+    public StatusBarNotification clone() {
+        return new StatusBarNotification(this.pkg, this.id, this.tag, this.notification.clone());
+    }
+
+    public String toString() {
+        return "StatusBarNotification(package=" + pkg + " id=" + id + " tag=" + tag
+                + " notification=" + notification + ")";
+    }
+
+    public boolean isOngoing() {
+        return (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0;
+    }
+
+}
+
+
diff --git a/core/java/com/android/internal/statusbar/StatusBarNotificationList.aidl b/core/java/com/android/internal/statusbar/StatusBarNotificationList.aidl
new file mode 100644
index 0000000..10abeee
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/StatusBarNotificationList.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.statusbar;
+
+parcelable StatusBarNotificationList;
+
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index dbad7e9..d4545d7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -122,6 +122,7 @@
 	android_server_BluetoothService.cpp \
 	android_server_BluetoothEventLoop.cpp \
 	android_server_BluetoothA2dpService.cpp \
+	android_server_Watchdog.cpp \
 	android_message_digest_sha1.cpp \
 	android_ddm_DdmHandleNativeHeap.cpp \
 	com_android_internal_os_ZygoteInit.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 76df9db..f66ed83 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -154,6 +154,7 @@
 extern int register_android_server_BluetoothService(JNIEnv* env);
 extern int register_android_server_BluetoothEventLoop(JNIEnv *env);
 extern int register_android_server_BluetoothA2dpService(JNIEnv* env);
+extern int register_android_server_Watchdog(JNIEnv* env);
 extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
 extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env);
 extern int register_android_backup_BackupDataInput(JNIEnv *env);
@@ -1278,6 +1279,7 @@
     REG_JNI(register_android_server_BluetoothService),
     REG_JNI(register_android_server_BluetoothEventLoop),
     REG_JNI(register_android_server_BluetoothA2dpService),
+    REG_JNI(register_android_server_Watchdog),
     REG_JNI(register_android_message_digest_sha1),
     REG_JNI(register_android_ddm_DdmHandleNativeHeap),
     REG_JNI(register_android_backup_BackupDataInput),
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
index cf53a06..8c795af 100644
--- a/core/jni/android_server_BluetoothA2dpService.cpp
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -256,10 +256,12 @@
                     parse_property_change(env, msg, (Properties *)&sink_properties,
                                 sizeof(sink_properties) / sizeof(Properties));
         const char *c_path = dbus_message_get_path(msg);
+        jstring path = env->NewStringUTF(c_path);
         env->CallVoidMethod(nat->me,
                             method_onSinkPropertyChanged,
-                            env->NewStringUTF(c_path),
+                            path,
                             str_array);
+        env->DeleteLocalRef(path);
         result = DBUS_HANDLER_RESULT_HANDLED;
         return result;
     } else {
@@ -292,10 +294,13 @@
         result = JNI_FALSE;
     }
     LOGV("... Device Path = %s, result = %d", path, result);
+
+    jstring jPath = env->NewStringUTF(path);
     env->CallVoidMethod(nat->me,
                         method_onConnectSinkResult,
-                        env->NewStringUTF(path),
+                        jPath,
                         result);
+    env->DeleteLocalRef(jPath);
     free(user);
 }
 
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 259cc01..01b6711 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -1061,6 +1061,8 @@
     DBusError err;
     dbus_error_init(&err);
     JNIEnv *env;
+    jstring addr;
+
     nat->vm->GetEnv((void**)&env, nat->envVer);
 
     LOGV("... address = %s", address);
@@ -1109,10 +1111,12 @@
         }
     }
 
+    addr = env->NewStringUTF(address);
     env->CallVoidMethod(nat->me,
                         method_onCreatePairedDeviceResult,
-                        env->NewStringUTF(address),
+                        addr,
                         result);
+    env->DeleteLocalRef(addr);
 done:
     dbus_error_free(&err);
     free(user);
@@ -1139,10 +1143,12 @@
         }
         LOG_AND_FREE_DBUS_ERROR(&err);
     }
+    jstring addr = env->NewStringUTF(address);
     env->CallVoidMethod(nat->me,
                         method_onCreateDeviceResult,
-                        env->NewStringUTF(address),
+                        addr,
                         result);
+    env->DeleteLocalRef(addr);
     free(user);
 }
 
@@ -1163,10 +1169,12 @@
         LOG_AND_FREE_DBUS_ERROR(&err);
         result = JNI_FALSE;
     }
+    jstring jPath = env->NewStringUTF(path);
     env->CallVoidMethod(nat->me,
                         method_onDiscoverServicesResult,
-                        env->NewStringUTF(path),
+                        jPath,
                         result);
+    env->DeleteLocalRef(jPath);
     free(user);
 }
 
@@ -1194,10 +1202,12 @@
     }
 
 done:
+    jstring addr = env->NewStringUTF(address);
     env->CallVoidMethod(nat->me,
                         method_onGetDeviceServiceChannelResult,
-                        env->NewStringUTF(address),
+                        addr,
                         channel);
+    env->DeleteLocalRef(addr);
     free(user);
 }
 #endif
diff --git a/core/jni/android_server_Watchdog.cpp b/core/jni/android_server_Watchdog.cpp
new file mode 100644
index 0000000..2a90db7
--- /dev/null
+++ b/core/jni/android_server_Watchdog.cpp
@@ -0,0 +1,111 @@
+/*
+ ** Copyright 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.
+ */
+
+#define LOG_TAG "Watchdog_N"
+#include <utils/Log.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <errno.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include <android_runtime/AndroidRuntime.h>
+
+static void dumpOneStack(int tid, int outFd) {
+    char buf[64];
+
+    snprintf(buf, sizeof(buf), "/proc/%d/stack", tid);
+    int stackFd = open(buf, O_RDONLY);
+    if (stackFd >= 0) {
+        // header for readability
+        strncat(buf, ":\n", sizeof(buf) - strlen(buf) - 1);
+        write(outFd, buf, strlen(buf));
+
+        // copy the stack dump text
+        int nBytes;
+        while ((nBytes = read(stackFd, buf, sizeof(buf))) > 0) {
+            write(outFd, buf, nBytes);
+        }
+
+        // footer and done
+        write(outFd, "\n", 1);
+        close(stackFd);
+    } else {
+        LOGE("Unable to open stack of tid %d : %d (%s)", tid, errno, strerror(errno));
+    }
+}
+
+static void dumpKernelStacks(JNIEnv* env, jobject clazz, jstring pathStr) {
+    char buf[128];
+    DIR* taskdir;
+
+    LOGI("dumpKernelStacks");
+    if (!pathStr) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Null path");
+        return;
+    }
+
+    const char *path = env->GetStringUTFChars(pathStr, NULL);
+
+    int outFd = open(path, O_WRONLY | O_APPEND | O_CREAT);
+    if (outFd < 0) {
+        LOGE("Unable to open stack dump file: %d (%s)", errno, strerror(errno));
+        goto done;
+    }
+
+    snprintf(buf, sizeof(buf), "\n----- begin pid %d kernel stacks -----\n", getpid());
+    write(outFd, buf, strlen(buf));
+
+    // look up the list of all threads in this process
+    snprintf(buf, sizeof(buf), "/proc/%d/task", getpid());
+    taskdir = opendir(buf);
+    if (taskdir != NULL) {
+        struct dirent * ent;
+        while ((ent = readdir(taskdir)) != NULL) {
+            int tid = atoi(ent->d_name);
+            if (tid > 0 && tid <= 65535) {
+                // dump each stack trace
+                dumpOneStack(tid, outFd);
+            }
+        }
+        closedir(taskdir);
+    }
+
+    snprintf(buf, sizeof(buf), "----- end pid %d kernel stacks -----\n", getpid());
+    write(outFd, buf, strlen(buf));
+
+    close(outFd);
+done:
+    env->ReleaseStringUTFChars(pathStr, path);
+}
+
+// ----------------------------------------
+
+namespace android {
+
+static const JNINativeMethod g_methods[] = {
+    { "native_dumpKernelStacks", "(Ljava/lang/String;)V", (void*)dumpKernelStacks },
+};
+
+int register_android_server_Watchdog(JNIEnv* env) {
+    return AndroidRuntime::registerNativeMethods(env, "com/android/server/Watchdog",
+                                                 g_methods, NELEM(g_methods));
+}
+
+}
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 838ef22..06fa84b 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "Surface"
+
 #include <stdio.h>
 
 #include "android_util_Binder.h"
@@ -226,8 +228,9 @@
         doThrow(env, "java/lang/NullPointerException", NULL);
         return;
     }
-    sp<Surface> rhs = new Surface(*parcel);
-    setSurface(env, clazz, rhs);
+
+    sp<Surface> sur(Surface::readFromParcel(*parcel, 0));
+    setSurface(env, clazz, sur);
 }
 
 static jint Surface_getIdentity(JNIEnv* env, jobject clazz)
@@ -586,7 +589,7 @@
      * a Surface and is necessary for returning the Surface reference to
      * the caller. At this point, we should only have a SurfaceControl.
      */
-    
+
     const sp<SurfaceControl>& surface = getSurfaceControl(env, clazz);
     const sp<SurfaceControl>& rhs = getSurfaceControl(env, other);
     if (!SurfaceControl::isSameSurface(surface, rhs)) {
@@ -605,13 +608,9 @@
         return;
     }
 
-    const sp<Surface>& control(getSurface(env, clazz));
-    sp<Surface> rhs = new Surface(*parcel);
-    if (!Surface::isSameSurface(control, rhs)) {
-        // we reassign the surface only if it's a different one
-        // otherwise we would loose our client-side state.
-        setSurface(env, clazz, rhs);
-    }
+    const sp<Surface>& curr(getSurface(env, clazz));
+    sp<Surface> sur(Surface::readFromParcel(*parcel, curr));
+    setSurface(env, clazz, sur);
 }
 
 static void Surface_writeToParcel(
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2a2208f..1fcf186 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1250,6 +1250,12 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
+        <activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
+                android:theme="@style/Theme.Dialog"
+                android:label="@string/heavy_weight_switcher_title"
+                android:finishOnCloseSystemDialogs="true"
+                android:excludeFromRecents="true">
+        </activity>
         <activity android:name="com.android.internal.app.DisableCarModeActivity"
                 android:theme="@style/Theme.NoDisplay"
                 android:excludeFromRecents="true">
diff --git a/core/res/res/drawable-hdpi/battery_charge_fill_empty.9.png b/core/res/res/drawable-hdpi/battery_charge_fill_empty.9.png
deleted file mode 100644
index c4e70a8..0000000
--- a/core/res/res/drawable-hdpi/battery_charge_fill_empty.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/battery_charge_fill_full.9.png b/core/res/res/drawable-hdpi/battery_charge_fill_full.9.png
deleted file mode 100644
index ac66f5a..0000000
--- a/core/res/res/drawable-hdpi/battery_charge_fill_full.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/battery_charge_fill_warning.9.png b/core/res/res/drawable-hdpi/battery_charge_fill_warning.9.png
deleted file mode 100644
index 32d99c6..0000000
--- a/core/res/res/drawable-hdpi/battery_charge_fill_warning.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_bluetooth.png b/core/res/res/drawable-hdpi/stat_sys_data_bluetooth.png
index 96dc085..7a8b78f 100644
--- a/core/res/res/drawable-hdpi/stat_sys_data_bluetooth.png
+++ b/core/res/res/drawable-hdpi/stat_sys_data_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/battery_charge_fill_full.9.png b/core/res/res/drawable-mdpi/battery_charge_fill_full.9.png
deleted file mode 100644
index 8e6aaca..0000000
--- a/core/res/res/drawable-mdpi/battery_charge_fill_full.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/battery_charge_fill_warning.9.png b/core/res/res/drawable-mdpi/battery_charge_fill_warning.9.png
deleted file mode 100644
index d3287db..0000000
--- a/core/res/res/drawable-mdpi/battery_charge_fill_warning.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/battery_charge_fill.xml b/core/res/res/drawable/battery_charge_fill.xml
deleted file mode 100644
index 7f65733..0000000
--- a/core/res/res/drawable/battery_charge_fill.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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.
--->
-
-<level-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:maxLevel="29" android:drawable="@android:drawable/battery_charge_fill_empty" />
-    <item android:maxLevel="49" android:drawable="@android:drawable/battery_charge_fill_warning" />
-    <item android:maxLevel="100" android:drawable="@android:drawable/battery_charge_fill_full" />
-</level-list>
-
diff --git a/core/res/res/layout/battery_status.xml b/core/res/res/layout/battery_status.xml
deleted file mode 100644
index 7cfec05..0000000
--- a/core/res/res/layout/battery_status.xml
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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:id="@+id/frame"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:orientation="vertical"
-    android:gravity="center_horizontal"
-    >
-    
-    <FrameLayout
-        android:layout_width="141px" 
-        android:layout_height="184px"
-        android:background="@drawable/battery_charge_background"
-        android:paddingTop="25px"
-        android:paddingLeft="1px"
-        >
-
-        <LinearLayout
-            android:id="@+id/meter"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="vertical"
-            >
-
-            <ImageView
-                android:layout_width="match_parent"
-                android:layout_height="15dip"
-                />
-            <ImageView
-                android:id="@+id/spacer"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                />
-            <ImageView
-                android:id="@+id/level"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-            />
-        
-        </LinearLayout>
-
-        <TextView android:id="@+id/level_percent"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:textStyle="bold"
-            android:textSize="48dp"
-            android:textColor="#ffffffff"
-            android:gravity="center"
-            />
-    </FrameLayout>
-
-    <TextView android:id="@+id/status"
-        android:paddingTop="35dp"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:singleLine="true"
-        android:textStyle="bold"
-        android:textSize="30dp"
-        android:textColor="#ffffffff"
-        android:gravity="center_horizontal"
-        android:text="@string/battery_status_charging"
-        />
-
-</LinearLayout>
-
-
diff --git a/core/res/res/layout/heavy_weight_switcher.xml b/core/res/res/layout/heavy_weight_switcher.xml
new file mode 100644
index 0000000..9acf009
--- /dev/null
+++ b/core/res/res/layout/heavy_weight_switcher.xml
@@ -0,0 +1,145 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical" android:padding="4dp"
+    android:gravity="center_horizontal"
+    android:layout_width="wrap_content" android:layout_height="wrap_content">
+
+    <TextView
+        android:layout_width="match_parent" android:layout_height="wrap_content"
+        android:layout_weight="0"
+        android:paddingBottom="8dp"
+        android:text="@string/heavy_weight_switcher_text"/>
+
+    <ImageView android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:scaleType="fitXY"
+        android:src="?android:listDivider" />
+            
+    <LinearLayout android:id="@+id/switch_old"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="?android:attr/listPreferredItemHeight"
+        android:orientation="horizontal"
+        android:background="@android:drawable/list_selector_background"
+        android:paddingRight="3dip"
+        android:paddingLeft="3dip"
+        android:paddingTop="5dip"
+        android:paddingBottom="14dip"
+        android:gravity="center_vertical"
+        android:focusable="true" >
+    
+        <ImageView android:id="@+id/old_app_icon"
+            android:layout_width="@android:dimen/app_icon_size"
+            android:layout_height="@android:dimen/app_icon_size"
+            android:layout_marginRight="11dip"
+            android:layout_gravity="center_vertical"
+            android:scaleType="fitCenter"/>
+    
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:duplicateParentState="true" >
+            <TextView android:id="@+id/old_app_action"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+                android:textStyle="bold"
+                android:singleLine="true"
+                android:layout_marginBottom="2dip"
+                android:duplicateParentState="true" />
+            <TextView android:id="@+id/old_app_description"
+                android:layout_marginTop="-4dip"
+                android:layout_gravity="center_vertical"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textAppearance="?android:attr/textAppearanceSmall"
+                android:duplicateParentState="true" />
+        </LinearLayout>
+    </LinearLayout>
+
+    <ImageView android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:scaleType="fitXY"
+        android:src="?android:listDivider" />
+            
+    <LinearLayout android:id="@+id/switch_new"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="?android:attr/listPreferredItemHeight"
+        android:orientation="horizontal"
+        android:background="@android:drawable/list_selector_background"
+        android:paddingRight="3dip"
+        android:paddingLeft="3dip"
+        android:paddingTop="5dip"
+        android:paddingBottom="8dip"
+        android:gravity="center_vertical"
+        android:focusable="true" >
+    
+        <ImageView android:id="@+id/new_app_icon"
+            android:layout_width="@android:dimen/app_icon_size"
+            android:layout_height="@android:dimen/app_icon_size"
+            android:layout_marginRight="11dip"
+            android:layout_gravity="center_vertical"
+            android:scaleType="fitCenter"/>
+    
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:duplicateParentState="true" >
+            <TextView android:id="@+id/new_app_action"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+                android:textStyle="bold"
+                android:singleLine="true"
+                android:layout_marginBottom="2dip"
+                android:duplicateParentState="true" />
+            <TextView android:id="@+id/new_app_description"
+                android:layout_marginTop="-4dip"
+                android:layout_gravity="center_vertical"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textAppearance="?android:attr/textAppearanceSmall"
+                android:duplicateParentState="true" />
+        </LinearLayout>
+    </LinearLayout>
+
+    <ImageView android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:scaleType="fitXY"
+        android:src="?android:listDivider" />
+
+    <TextView android:id="@+id/cancel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="?android:attr/listPreferredItemHeight"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:background="@android:drawable/list_selector_background"
+        android:paddingRight="6dip"
+        android:paddingLeft="6dip"
+        android:paddingTop="5dip"
+        android:paddingBottom="8dip"
+        android:textStyle="bold"
+        android:singleLine="true"
+        android:gravity="center"
+        android:focusable="true"
+        android:text="@string/cancel" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/status_bar_latest_event_content.xml b/core/res/res/layout/status_bar_latest_event_content.xml
index ea6200a..c64b90e 100644
--- a/core/res/res/layout/status_bar_latest_event_content.xml
+++ b/core/res/res/layout/status_bar_latest_event_content.xml
@@ -12,7 +12,8 @@
         android:orientation="horizontal"
         android:paddingTop="3dp"
         >
-        <com.android.server.status.AnimatedImageView android:id="@+id/icon"
+        <!--com.android.server.status.AnimatedImageView android:id="@+id/icon" -->
+        <ImageView android:id="@+id/icon"
             android:layout_width="25dp"
             android:layout_height="25dp"
             android:scaleType="fitCenter"
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index a0bc5b3..04937565 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -120,25 +120,25 @@
     <!-- Do not translate. Defines the slots for the right-hand side icons.  That is to say, the
          icons in the status bar that are not notifications. -->
     <string-array name="status_bar_icon_order">
-        <item><xliff:g id="id">clock</xliff:g></item>
-        <item><xliff:g id="id">secure</xliff:g></item>
-        <item><xliff:g id="id">alarm_clock</xliff:g></item>
-        <item><xliff:g id="id">battery</xliff:g></item>
-        <item><xliff:g id="id">phone_signal</xliff:g></item>
-        <item><xliff:g id="id">phone_evdo_signal</xliff:g></item>
-        <item><xliff:g id="id">data_connection</xliff:g></item>
-        <item><xliff:g id="id">cdma_eri</xliff:g></item>
-        <item><xliff:g id="id">wifi</xliff:g></item>
-        <item><xliff:g id="id">tty</xliff:g></item>
-        <item><xliff:g id="id">volume</xliff:g></item>
-        <item><xliff:g id="id">mute</xliff:g></item>
-        <item><xliff:g id="id">speakerphone</xliff:g></item>
-        <item><xliff:g id="id">tty</xliff:g></item>
-        <item><xliff:g id="id">bluetooth</xliff:g></item>
-        <item><xliff:g id="id">gps</xliff:g></item>
-        <item><xliff:g id="id">sync_active</xliff:g></item>
-        <item><xliff:g id="id">sync_failing</xliff:g></item>
-        <item><xliff:g id="id">ime</xliff:g></item>
+       <item><xliff:g id="id">ime</xliff:g></item>
+       <item><xliff:g id="id">sync_failing</xliff:g></item>
+       <item><xliff:g id="id">sync_active</xliff:g></item>
+       <item><xliff:g id="id">gps</xliff:g></item>
+       <item><xliff:g id="id">bluetooth</xliff:g></item>
+       <item><xliff:g id="id">tty</xliff:g></item>
+       <item><xliff:g id="id">speakerphone</xliff:g></item>
+       <item><xliff:g id="id">mute</xliff:g></item>
+       <item><xliff:g id="id">volume</xliff:g></item>
+       <item><xliff:g id="id">tty</xliff:g></item>
+       <item><xliff:g id="id">wifi</xliff:g></item>
+       <item><xliff:g id="id">cdma_eri</xliff:g></item>
+       <item><xliff:g id="id">data_connection</xliff:g></item>
+       <item><xliff:g id="id">phone_evdo_signal</xliff:g></item>
+       <item><xliff:g id="id">phone_signal</xliff:g></item>
+       <item><xliff:g id="id">battery</xliff:g></item>
+       <item><xliff:g id="id">alarm_clock</xliff:g></item>
+       <item><xliff:g id="id">secure</xliff:g></item>
+       <item><xliff:g id="id">clock</xliff:g></item>
     </string-array>
 
 </resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b4c4811..5ca7b28 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -740,6 +740,15 @@
         <attr name="restoreNeedsApplication" />
         <attr name="restoreAnyVersion" />
         <attr name="neverEncrypt" />
+        <!-- Declare that this is a heavy-weight application.  This kind of
+             application is not able to save and restore its state on demand,
+             so can not participate in the normal activity lifecycle.  It will
+             not be killed while in the background; the user must explicitly
+             quit it.  Only one such app can be running at a time; if the user
+             tries to launch a second heavy-weight app, they will be prompted
+             to quit the first before doing so.  While a heavy-weight
+             application is running, the user will be informed of this. -->
+        <attr name="heavyWeight" format="boolean" />
     </declare-styleable>
     
     <!-- The <code>permission</code> tag declares a security permission that can be
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 64f05fe..1946388 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -91,8 +91,18 @@
     <string-array translatable="false" name="config_tether_upstream_regexs">
     </string-array>
 
-    <!-- Boolean indicating if we require the use of DUN on mobile for tethering -->
-    <bool translatable="false" name="config_tether_dun_required">true</bool>
+    <!-- Boolean indicating if we require the use of DUN on mobile for tethering.
+         Note that this defaults to false so that if you move to a carrier that
+         hasn't configured anything tethering will still work.  If you'd rather
+         make the device untetherable on unconfigured devices, set to true -->
+    <bool translatable="false" name="config_tether_dun_required">false</bool>
+
+    <!-- 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"></string>
+
 
     <!-- Flag indicating whether the keyguard should be bypassed when
          the slider is open.  This can be set or unset depending how easily
@@ -220,9 +230,6 @@
     <!-- Allow the menu hard key to be disabled in LockScreen on some devices -->
     <bool name="config_disableMenuKeyInLockScreen">false</bool>
 
-    <!-- Control whether status bar should distinguish HSPA data icon form UMTS data icon on devices -->
-    <bool name="config_hspa_data_distinguishable">false</bool>
-
     <!-- Array of light sensor LUX values to define our levels for auto backlight brightness support.
          The N entries of this array define N + 1 zones as follows:
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5d18e9e..1932771 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1245,8 +1245,9 @@
      
   <public type="attr" name="logo" id="0x010102be" />
   <public type="attr" name="xlargeScreens" id="0x010102bf" />
-
+  <public type="attr" name="heavyWeight" id="0x010102c0" />
   <public-padding type="attr" name="kraken_resource_pad" end="0x01010300" />
+  
   <public-padding type="id" name="kraken_resource_pad" end="0x01020040" />
   <public-padding type="anim" name="kraken_resource_pad" end="0x010a0020" />
   <public-padding type="drawable" name="kraken_resource_pad" end="0x01080100" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1e007d36..e7f892a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1567,45 +1567,6 @@
     <!-- A format string for 12-hour time of day, just the hour, not the minute, with capital "AM" or "PM" (example: "3PM"). -->
     <string name="hour_cap_ampm">"<xliff:g id="hour" example="3">%-l</xliff:g><xliff:g id="ampm" example="PM">%p</xliff:g>"</string>
 
-    <!-- The text for the button in the notification window-shade that clears
-         all of the currently visible notifications. -->
-    <string name="status_bar_clear_all_button">Clear</string>
-
-    <!-- The label in the bar at the top of the status bar when there are no notifications
-         showing. -->
-    <string name="status_bar_no_notifications_title">No notifications</string>
-
-    <!-- The label for the group of notifications for ongoing events in the opened version of
-         the status bar.  An ongoing call is the prime example of this.  The MP3 music player
-         might be another example.  -->
-    <string name="status_bar_ongoing_events_title">Ongoing</string>
-
-    <!-- The label for the group of notifications for recent events in the opened version of
-         the status bar.  Recently received text messsages (SMS), emails, calendar alerts, etc. -->
-    <string name="status_bar_latest_events_title">Notifications</string>
-
-    <!-- The big percent text in the middle of the battery icon that appears when you plug in
-         the charger. -->
-    <string name="battery_status_text_percent_format"><xliff:g id="number" example="50">%d</xliff:g><xliff:g id="percent" example="%">%%</xliff:g></string>
-
-    <!-- The big percent text in the middle of the battery icon that appears when you plug in
-         the charger. This indicates the current status of the battery.  -->
-    <string name="battery_status_charging">Charging\u2026</string>
-
-    <!-- When the battery is low, this is displayed to the user in a dialog.  The title of the low battery alert. -->
-    <string name="battery_low_title">Please connect charger</string>
-
-    <!-- When the battery is low, this is displayed to the user in a dialog. The subtitle of the low battery alert. -->
-    <string name="battery_low_subtitle">The battery is getting low:</string>
-
-    <!-- A message that appears when the battery level is getting low in a dialog.  This is appened to the subtitle of the low battery alert. -->
-    <string name="battery_low_percent_format"><xliff:g id="number">%d%%</xliff:g>
-    or less remaining.</string>
-
-    <!-- When the battery is low, this is the label of the button to go to the
-         power usage activity to find out what drained the battery. -->
-    <string name="battery_low_why">Battery use</string>
-
     <!-- Title of the alert when something went wrong in the factory test. -->
     <string name="factorytest_failed">Factory test failed</string>
     <!-- Error message displayed when a non-system application tries to start a factory test. -->
@@ -1974,8 +1935,29 @@
     <!-- Button allowing the user to choose to wait for an application that is not responding to become responsive again. -->
     <string name="wait">Wait</string>
 
+    <!-- Notification text to tell the user that a heavy-weight application is running. -->
+    <string name="heavy_weight_notification"><xliff:g id="app">%1$s</xliff:g> running</string>
+    
+    <!-- Notification details to tell the user that a heavy-weight application is running. -->
+    <string name="heavy_weight_notification_detail">Select to switch to application</string>
+    
+    <!-- Title of dialog prompting whether user wants to switch between heavy-weight apps. -->
+    <string name="heavy_weight_switcher_title">Switch applications?</string>
+    
+    <!-- Descriptive text for switching to a new heavy-weight application. -->
+    <string name="heavy_weight_switcher_text">Another application is already running
+    that must be stopped before you can start a new one.</string>
+    
+    <string name="old_app_action">Return to <xliff:g id="old_app">%1$s</xliff:g></string>
+    <string name="old_app_description">Don\'t start the new application.</string>
+    
+    <string name="new_app_action">Start <xliff:g id="old_app">%1$s</xliff:g></string>
+    <string name="new_app_description">Stop the old application without saving.</string>
+    
     <!-- Displayed in the title of the chooser for things to do with text that
-         is to be sent to another application. For example, I can send text through SMS or IM.  A dialog with those choices would be shown, and this would be the title. -->
+         is to be sent to another application. For example, I can send
+         text through SMS or IM.  A dialog with those choices would be shown,
+         and this would be the title. -->
     <string name="sendText">Select an action for text</string>
 
     <!-- Title of the dialog where the user is adjusting the phone ringer volume -->
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index 5b427be..a5229cc 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -26,6 +26,8 @@
 import android.text.TextPaint;
 import android.text.TextUtils;
 import android.text.style.StyleSpan;
+import android.text.util.Rfc822Token;
+import android.text.util.Rfc822Tokenizer;
 import android.test.MoreAsserts;
 
 import com.android.common.Rfc822Validator;
@@ -269,6 +271,24 @@
         }
     }
 
+    @SmallTest
+    public void testRfc822TokenizerFullAddress() {
+        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize("Foo Bar (something) <foo@google.com>");
+        assertNotNull(tokens);
+        assertEquals(1, tokens.length);
+        assertEquals("foo@google.com", tokens[0].getAddress());
+        assertEquals("Foo Bar", tokens[0].getName());
+        assertEquals("something",tokens[0].getComment());
+    }
+
+    @SmallTest
+    public void testRfc822TokenizeItemWithError() {
+        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize("\"Foo Bar\\");
+        assertNotNull(tokens);
+        assertEquals(1, tokens.length);
+        assertEquals("Foo Bar", tokens[0].getAddress());
+    }
+
     @LargeTest
     public void testEllipsize() {
         CharSequence s1 = "The quick brown fox jumps over \u00FEhe lazy dog.";
diff --git a/docs/html/guide/topics/security/security.jd b/docs/html/guide/topics/security/security.jd
index da201c4..dbc9866 100644
--- a/docs/html/guide/topics/security/security.jd
+++ b/docs/html/guide/topics/security/security.jd
@@ -40,15 +40,14 @@
 e-mails), reading or writing another application's files, performing
 network access, keeping the device awake, etc.<p>
 
-<p>An application's process is a secure sandbox.  It can't disrupt other
-applications, except by explicitly declaring the <em>permissions</em> it needs
-for additional capabilities not provided by the basic sandbox.  These
-permissions it requests can be handled by the operating in various ways,
-typically by automatically allowing or disallowing based on certificates or
-by prompting the user.  The permissions required by an application are declared
-statically in that application, so they can be known up-front at install time
-and will not change after that.</p>
-
+<p>An application's process runs in a security sandbox. The sandbox is designed
+to prevent applications from disrupting each other, except by explicitly
+declaring the <em>permissions</em> they need for additional capabilities not
+provided by the basic sandbox. The system handles requests for permissions
+in various ways, typically by automatically allowing or disallowing based on
+certificates or by prompting the user.  The permissions required by an
+application are declared statically in that application, so they can be known
+up-front at install time and will not change after that.</p>
 
 <a name="signing"></a>
 <h2>Application Signing</h2>
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 2b7a86eb..e12a694 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -250,6 +250,13 @@
     // Example value: "yuv420sp" or PIXEL_FORMAT_XXX constants. Read only.
     static const char KEY_VIDEO_FRAME_FORMAT[];
 
+    // Metering mode. This affects how camera determines exposure.
+    // Example value: "spot" or METERING_MODE_XXX constants. Read/write.
+    static const char KEY_METERING_MODE[];
+    // Supported metering modes.
+    // Example value: "center-weighted,frame-average,spot". Read only.
+    static const char KEY_SUPPORTED_METERING_MODES[];
+
     // Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED.
     static const char TRUE[];
 
@@ -347,6 +354,15 @@
     // callback will be only called once as soon as the picture is in focus.
     static const char FOCUS_MODE_CONTINUOUS[];
 
+    // The camera determines the exposure by giving more weight to the
+    // central part of the scene.
+    static const char METERING_MODE_CENTER_WEIGHTED[];
+    // The camera determines the exposure by averaging the entire scene,
+    // giving no weighting to any particular area.
+    static const char METERING_MODE_FRAME_AVERAGE[];
+    // The camera determines the exposure by a very small area of the scene,
+    // typically the center.
+    static const char METERING_MODE_SPOT[];
 
 private:
     DefaultKeyedVector<String8,String8>    mMap;
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 92bc126..d956882 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -142,7 +142,8 @@
                                     uint32_t flags      = 0,
                                     callback_t cbf = 0,
                                     void* user = 0,
-                                    int notificationFrames = 0);
+                                    int notificationFrames = 0,
+                                    int sessionId = 0);
 
 
     /* Terminates the AudioRecord and unregisters it from AudioFlinger.
@@ -168,7 +169,8 @@
                             callback_t cbf = 0,
                             void* user = 0,
                             int notificationFrames = 0,
-                            bool threadCanCallJava = false);
+                            bool threadCanCallJava = false,
+                            int sessionId = 0);
 
 
     /* Result of constructing the AudioRecord. This must be checked
@@ -270,6 +272,16 @@
      */
             audio_io_handle_t    getInput();
 
+    /* returns the audio session ID associated to this AudioRecord.
+     *
+     * Parameters:
+     *  none.
+     *
+     * Returned value:
+     *  AudioRecord session ID.
+     */
+            int    getSessionId();
+
     /* obtains a buffer of "frameCount" frames. The buffer must be
      * filled entirely. If the track is stopped, obtainBuffer() returns
      * STOPPED instead of NO_ERROR as long as there are buffers availlable,
@@ -356,6 +368,7 @@
     uint32_t                mFlags;
     uint32_t                mChannels;
     audio_io_handle_t       mInput;
+    int                     mSessionId;
 };
 
 }; // namespace android
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 9caef8f..f21e83d 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -230,6 +230,8 @@
     static status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int stream = DEFAULT);
 
     static unsigned int  getInputFramesLost(audio_io_handle_t ioHandle);
+
+    static int newAudioSessionId();
     //
     // AudioPolicyService interface
     //
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index cc4ab74..c46df1e 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -138,7 +138,8 @@
                                     uint32_t flags       = 0,
                                     callback_t cbf       = 0,
                                     void* user           = 0,
-                                    int notificationFrames = 0);
+                                    int notificationFrames = 0,
+                                    int sessionId = 0);
 
     /* Creates an audio track and registers it with AudioFlinger. With this constructor,
      * The PCM data to be rendered by AudioTrack is passed in a shared memory buffer
@@ -157,7 +158,8 @@
                                     uint32_t flags      = 0,
                                     callback_t cbf      = 0,
                                     void* user          = 0,
-                                    int notificationFrames = 0);
+                                    int notificationFrames = 0,
+                                    int sessionId = 0);
 
     /* Terminates the AudioTrack and unregisters it from AudioFlinger.
      * Also destroys all resources assotiated with the AudioTrack.
@@ -182,7 +184,8 @@
                             void* user          = 0,
                             int notificationFrames = 0,
                             const sp<IMemory>& sharedBuffer = 0,
-                            bool threadCanCallJava = false);
+                            bool threadCanCallJava = false,
+                            int sessionId = 0);
 
 
     /* Result of constructing the AudioTrack. This must be checked
@@ -239,10 +242,17 @@
 
 
     /* set volume for this track, mostly used for games' sound effects
+     * left and right volumes. Levels must be <= 1.0.
      */
-            void        setVolume(float left, float right);
+            status_t    setVolume(float left, float right);
             void        getVolume(float* left, float* right);
 
+    /* set the send level for this track. An auxiliary effect should be attached
+     * to the track with attachEffect(). Level must be <= 1.0.
+     */
+            status_t    setSendLevel(float level);
+            void        getSendLevel(float* level);
+
     /* set sample rate for this track, mostly used for games' sound effects
      */
             status_t    setSampleRate(int sampleRate);
@@ -340,6 +350,31 @@
      */
             audio_io_handle_t    getOutput();
 
+    /* returns the unique ID associated to this track.
+     *
+     * Parameters:
+     *  none.
+     *
+     * Returned value:
+     *  AudioTrack ID.
+     */
+            int    getSessionId();
+
+
+    /* Attach track auxiliary output to specified effect. Used effectId = 0
+     * to detach track from effect.
+     *
+     * Parameters:
+     *
+     * effectId:  effectId obtained from AudioEffect::id().
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - INVALID_OPERATION: the effect is not an auxiliary effect.
+     *  - BAD_VALUE: The specified effect ID is invalid
+     */
+            status_t    attachAuxEffect(int effectId);
+
     /* obtains a buffer of "frameCount" frames. The buffer must be
      * filled entirely. If the track is stopped, obtainBuffer() returns
      * STOPPED instead of NO_ERROR as long as there are buffers availlable,
@@ -406,6 +441,7 @@
     sp<AudioTrackThread>    mAudioTrackThread;
 
     float                   mVolume[2];
+    float                   mSendLevel;
     uint32_t                mFrameCount;
 
     audio_track_cblk_t*     mCblk;
@@ -431,6 +467,7 @@
     uint32_t                mNewPosition;
     uint32_t                mUpdatePeriod;
     uint32_t                mFlags;
+    int                     mSessionId;
 };
 
 
diff --git a/include/media/EffectApi.h b/include/media/EffectApi.h
index a1bc3b82..97874f7 100644
--- a/include/media/EffectApi.h
+++ b/include/media/EffectApi.h
@@ -114,7 +114,8 @@
 //  +---------------------------+-----------+-----------------------------------
 //  | Volume management         | 5..6      | 0 none
 //  |                           |           | 1 implements volume control
-//  |                           |           | 2..3 reserved
+//  |                           |           | 2 requires volume indication
+//  |                           |           | 3 reserved
 //  +---------------------------+-----------+-----------------------------------
 //  | Device management         | 7..8      | 0 none
 //  |                           |           | 1 requires device updates
@@ -154,6 +155,7 @@
 // volume control
 #define EFFECT_FLAG_VOLUME_MASK         0x00000060
 #define EFFECT_FLAG_VOLUME_CTRL         0x00000020
+#define EFFECT_FLAG_VOLUME_IND          0x00000040
 #define EFFECT_FLAG_VOLUME_NONE         0x00000000
 
 // device control
@@ -296,10 +298,12 @@
 //  | Set and get volume. Used by    | EFFECT_CMD_SET_VOLUME         | size: n * sizeof(uint32_t)    | size: n * sizeof(uint32_t)
 //  | audio framework to delegate    |                               | data: volume for each channel | data: volume for each channel
 //  | volume control to effect engine|                               | defined in effect_config_t in | defined in effect_config_t in
-//  | The engine must return the     |                               | 8.24 fixed point format       | 8.24 fixed point format
-//  | volume that should be applied  |                               |                               |
-//  | before the effect is processed |                               |                               |
-//  | The overall volume (the volume |                               |                               |
+//  | If volume control flag is set  |                               | 8.24 fixed point format       | 8.24 fixed point format
+//  | in the effect descriptor, the  |                               |                               | It is legal to receive a null
+//  | effect engine must return the  |                               |                               | pointer as pReplyData in which
+//  | volume that should be applied  |                               |                               | case the effect framework has
+//  | before the effect is processed |                               |                               | delegated volume control to
+//  | The overall volume (the volume |                               |                               | another effect.
 //  | actually applied by the effect |                               |                               |
 //  | multiplied by the returned     |                               |                               |
 //  | value) should match the        |                               |                               |
@@ -370,7 +374,7 @@
 // structure that defines both input and output buffer configurations and is
 // passed by the EFFECT_CMD_CONFIGURE command.
 typedef struct buffer_config_s {
-    audio_buffer_t  buffer;     // buffer for use by process() function is not passed explicitly
+    audio_buffer_t  buffer;     // buffer for use by process() function if not passed explicitly
     uint32_t   samplingRate;    // sampling rate
     uint32_t   channels;        // channel mask (see audio_channels_e in AudioCommon.h)
     buffer_provider_t bufferProvider;   // buffer provider
@@ -457,7 +461,7 @@
 //
 //    Function:       EffectQueryNumberEffects
 //
-//    Description:    Returns the number of different effect exposed by the
+//    Description:    Returns the number of different effects exposed by the
 //          library. Each effect must have a unique effect uuid (see
 //          effect_descriptor_t). This function together with EffectQueryNext()
 //          is used to enumerate all effects present in the library.
@@ -475,7 +479,7 @@
 //        *pNumEffects:     updated with number of effects in library
 //
 ////////////////////////////////////////////////////////////////////////////////
-typedef int32_t (*effect_QueryNumberEffects_t)(int32_t *pNumEffects);
+typedef int32_t (*effect_QueryNumberEffects_t)(uint32_t *pNumEffects);
 
 ////////////////////////////////////////////////////////////////////////////////
 //
@@ -521,7 +525,7 @@
 //        returned value:    0          successful operation.
 //                          -ENODEV     library failed to initialize
 //                          -EINVAL     invalid pEffectUuid or pInterface
-//                          -ENOENT     No effect with this uuid found
+//                          -ENOENT     no effect with this uuid found
 //        *pInterface:     updated with the effect interface handle.
 //
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/include/media/EffectFactoryApi.h b/include/media/EffectFactoryApi.h
index 8179c23..6cc9932 100644
--- a/include/media/EffectFactoryApi.h
+++ b/include/media/EffectFactoryApi.h
@@ -34,7 +34,7 @@
 //
 //    Function:       EffectQueryNumberEffects
 //
-//    Description:    Returns the number of different effect in all loaded libraries.
+//    Description:    Returns the number of different effects in all loaded libraries.
 //          Each effect must have a different effect uuid (see
 //          effect_descriptor_t). This function together with EffectQueryNext()
 //          is used to enumerate all effects present in all loaded libraries.
@@ -52,7 +52,7 @@
 //        *pNumEffects:     updated with number of effects in factory
 //
 ////////////////////////////////////////////////////////////////////////////////
-int EffectQueryNumberEffects(int *pNumEffects);
+int EffectQueryNumberEffects(uint32_t *pNumEffects);
 
 ////////////////////////////////////////////////////////////////////////////////
 //
@@ -98,7 +98,7 @@
 //        returned value:    0          successful operation.
 //                          -ENODEV     factory failed to initialize
 //                          -EINVAL     invalid pEffectUuid or pInterface
-//                          -ENOENT     No effect with this uuid found
+//                          -ENOENT     no effect with this uuid found
 //        *pInterface:     updated with the effect interface.
 //
 ////////////////////////////////////////////////////////////////////////////////
@@ -140,7 +140,7 @@
 //
 //    Output:
 //        returned value:    0          successful operation.
-//                          -ENODEV     Effect factory not initialized or
+//                          -ENODEV     effect factory not initialized or
 //                                      library could not be loaded or
 //                                      library does not implement required functions
 //                          -EINVAL     invalid libPath string or handle
@@ -159,7 +159,7 @@
 //
 //    Output:
 //        returned value:    0          successful operation.
-//                          -ENODEV     Effect factory not initialized
+//                          -ENODEV     effect factory not initialized
 //                          -ENOENT     invalid handle
 //
 ////////////////////////////////////////////////////////////////////////////////
@@ -184,7 +184,7 @@
 //        returned value:    0          successful operation.
 //                          -ENODEV     factory failed to initialize
 //                          -EINVAL     invalid pEffectUuid or pDescriptor
-//                          -ENOENT     No effect with this uuid found
+//                          -ENOENT     no effect with this uuid found
 //        *pDescriptor:     updated with the effect descriptor.
 //
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index c147632..ccfa530 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -27,6 +27,9 @@
 #include <media/IAudioTrack.h>
 #include <media/IAudioRecord.h>
 #include <media/IAudioFlingerClient.h>
+#include <media/EffectApi.h>
+#include <media/IEffect.h>
+#include <media/IEffectClient.h>
 #include <utils/String8.h>
 
 namespace android {
@@ -51,6 +54,7 @@
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 int output,
+                                int *sessionId,
                                 status_t *status) = 0;
 
     virtual sp<IAudioRecord> openRecord(
@@ -61,6 +65,7 @@
                                 int channelCount,
                                 int frameCount,
                                 uint32_t flags,
+                                int *sessionId,
                                 status_t *status) = 0;
 
     /* query the audio hardware state. This state never changes,
@@ -134,6 +139,28 @@
     virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output) = 0;
 
     virtual unsigned int  getInputFramesLost(int ioHandle) = 0;
+
+    virtual int newAudioSessionId() = 0;
+
+    virtual status_t loadEffectLibrary(const char *libPath, int *handle) = 0;
+
+    virtual status_t unloadEffectLibrary(int handle) = 0;
+
+    virtual status_t queryNumberEffects(uint32_t *numEffects) = 0;
+
+    virtual status_t queryNextEffect(effect_descriptor_t *pDescriptor) = 0;
+
+    virtual status_t getEffectDescriptor(effect_uuid_t *pEffectUUID, effect_descriptor_t *pDescriptor) = 0;
+
+    virtual sp<IEffect> createEffect(pid_t pid,
+                                    effect_descriptor_t *pDesc,
+                                    const sp<IEffectClient>& client,
+                                    int32_t priority,
+                                    int output,
+                                    int sessionId,
+                                    status_t *status,
+                                    int *id,
+                                    int *enabled) = 0;
 };
 
 
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index de6426a..47d530b 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -62,6 +62,11 @@
      */
     virtual void        pause() = 0;
 
+    /* Attach track auxiliary output to specified effect. Use effectId = 0
+     * to detach track from effect.
+     */
+    virtual status_t    attachAuxEffect(int effectId) = 0;
+
     /* get this tracks control block */
     virtual sp<IMemory> getCblk() const = 0;    
 };
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 0c7bf6f..0a7023a 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -51,6 +51,7 @@
     friend class CameraSourceListener;
 
     sp<Camera> mCamera;
+    sp<MetaData> mMeta;
 
     Mutex mLock;
     Condition mFrameAvailableCondition;
@@ -59,7 +60,6 @@
     List<sp<IMemory> > mFramesBeingEncoded;
     List<int64_t> mFrameTimes;
 
-    int mWidth, mHeight;
     int64_t mFirstFrameTimeUs;
     int64_t mLastFrameTimestampUs;
     int32_t mNumFramesReceived;
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index a9a0d55..9cddab2 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -40,6 +40,7 @@
 extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;
 extern const char *MEDIA_MIMETYPE_CONTAINER_OGG;
 extern const char *MEDIA_MIMETYPE_CONTAINER_MATROSKA;
+extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS;
 
 }  // namespace android
 
diff --git a/include/media/stagefright/foundation/AAtomizer.h b/include/media/stagefright/foundation/AAtomizer.h
new file mode 100644
index 0000000..5f3a678
--- /dev/null
+++ b/include/media/stagefright/foundation/AAtomizer.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#ifndef A_ATOMIZER_H_
+
+#define A_ATOMIZER_H_
+
+#include <stdint.h>
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AString.h>
+#include <utils/List.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct AAtomizer {
+    static const char *Atomize(const char *name);
+
+private:
+    static AAtomizer gAtomizer;
+
+    Mutex mLock;
+    Vector<List<AString> > mAtoms;
+
+    AAtomizer();
+
+    const char *atomize(const char *name);
+
+    static uint32_t Hash(const char *s);
+
+    DISALLOW_EVIL_CONSTRUCTORS(AAtomizer);
+};
+
+}  // namespace android
+
+#endif  // A_ATOMIZER_H_
diff --git a/services/java/com/android/server/status/StatusBarException.java b/include/media/stagefright/foundation/ABase.h
similarity index 71%
rename from services/java/com/android/server/status/StatusBarException.java
rename to include/media/stagefright/foundation/ABase.h
index be58f59..9eceea3 100644
--- a/services/java/com/android/server/status/StatusBarException.java
+++ b/include/media/stagefright/foundation/ABase.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * 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.
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+#ifndef A_BASE_H_
 
-public class StatusBarException extends RuntimeException {
-    StatusBarException(String msg) {
-        super(msg);
-    }
-}
+#define A_BASE_H_
+
+#define DISALLOW_EVIL_CONSTRUCTORS(name) \
+    name(const name &); \
+    name &operator=(const name &)
+
+#endif  // A_BASE_H_
diff --git a/include/media/stagefright/foundation/ABuffer.h b/include/media/stagefright/foundation/ABuffer.h
new file mode 100644
index 0000000..28f0aed
--- /dev/null
+++ b/include/media/stagefright/foundation/ABuffer.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#ifndef A_BUFFER_H_
+
+#define A_BUFFER_H_
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct AMessage;
+
+struct ABuffer : public RefBase {
+    ABuffer(size_t capacity);
+    ABuffer(void *data, size_t capacity);
+
+    void setFarewellMessage(const sp<AMessage> msg);
+
+    uint8_t *base() { return (uint8_t *)mData; }
+    uint8_t *data() { return (uint8_t *)mData + mRangeOffset; }
+    size_t capacity() const { return mCapacity; }
+    size_t size() const { return mRangeLength; }
+    size_t offset() const { return mRangeOffset; }
+
+    void setRange(size_t offset, size_t size);
+
+    void setInt32Data(int32_t data) { mInt32Data = data; }
+    int32_t int32Data() const { return mInt32Data; }
+
+    sp<AMessage> meta();
+
+protected:
+    virtual ~ABuffer();
+
+private:
+    sp<AMessage> mFarewell;
+    sp<AMessage> mMeta;
+
+    void *mData;
+    size_t mCapacity;
+    size_t mRangeOffset;
+    size_t mRangeLength;
+
+    int32_t mInt32Data;
+
+    bool mOwnsData;
+
+    DISALLOW_EVIL_CONSTRUCTORS(ABuffer);
+};
+
+}  // namespace android
+
+#endif  // A_BUFFER_H_
diff --git a/include/media/stagefright/foundation/ADebug.h b/include/media/stagefright/foundation/ADebug.h
new file mode 100644
index 0000000..0f986a0
--- /dev/null
+++ b/include/media/stagefright/foundation/ADebug.h
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#ifndef A_DEBUG_H_
+
+#define A_DEBUG_H_
+
+#include <string.h>
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AString.h>
+
+namespace android {
+
+enum LogType {
+    VERBOSE,
+    INFO,
+    WARNING,
+    ERROR,
+    FATAL,
+};
+
+struct Logger {
+    Logger(LogType type);
+    virtual ~Logger();
+
+    template<class T> Logger &operator<<(const T &x) {
+        mMessage.append(x);
+
+        return *this;
+    }
+
+private:
+    android::AString mMessage;
+    LogType mLogType;
+
+    DISALLOW_EVIL_CONSTRUCTORS(Logger);
+};
+
+const char *LeafName(const char *s);
+
+#undef LOG
+#define LOG(type)    Logger(type) << LeafName(__FILE__) << ":" << __LINE__ << " "
+
+#define CHECK(condition)                                \
+    do {                                                \
+        if (!(condition)) {                             \
+            LOG(FATAL) << "CHECK(" #condition ") failed.";    \
+        }                                               \
+    } while (false)
+
+#define MAKE_COMPARATOR(suffix,op)                          \
+    template<class A, class B>                              \
+    AString Compare_##suffix(const A &a, const B &b) {      \
+        AString res;                                        \
+        if (!(a op b)) {                                    \
+            res.append(a);                                  \
+            res.append(" vs. ");                            \
+            res.append(b);                                  \
+        }                                                   \
+        return res;                                         \
+    }
+
+MAKE_COMPARATOR(EQ,==)
+MAKE_COMPARATOR(NE,!=)
+MAKE_COMPARATOR(LE,<=)
+MAKE_COMPARATOR(GE,>=)
+MAKE_COMPARATOR(LT,<)
+MAKE_COMPARATOR(GT,>)
+
+#define CHECK_OP(x,y,suffix,op)                                         \
+    do {                                                                \
+        AString ___res = Compare_##suffix(x, y);                        \
+        if (!___res.empty()) {                                          \
+            LOG(FATAL) << "CHECK_" #suffix "(" #x "," #y ") failed: "   \
+                       << ___res;                                       \
+        }                                                               \
+    } while (false)
+
+#define CHECK_EQ(x,y)   CHECK_OP(x,y,EQ,==)
+#define CHECK_NE(x,y)   CHECK_OP(x,y,NE,!=)
+#define CHECK_LE(x,y)   CHECK_OP(x,y,LE,<=)
+#define CHECK_LT(x,y)   CHECK_OP(x,y,LT,<)
+#define CHECK_GE(x,y)   CHECK_OP(x,y,GE,>=)
+#define CHECK_GT(x,y)   CHECK_OP(x,y,GT,>)
+
+#define TRESPASS()      LOG(FATAL) << "Should not be here."
+
+}  // namespace android
+
+#endif  // A_DEBUG_H_
+
diff --git a/include/media/stagefright/foundation/AHandler.h b/include/media/stagefright/foundation/AHandler.h
new file mode 100644
index 0000000..9fccead
--- /dev/null
+++ b/include/media/stagefright/foundation/AHandler.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#ifndef A_HANDLER_H_
+
+#define A_HANDLER_H_
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct AMessage;
+
+struct AHandler : public RefBase {
+    AHandler()
+        : mID(0) {
+    }
+
+    ALooper::handler_id id() const {
+        return mID;
+    }
+
+protected:
+    virtual void onMessageReceived(const sp<AMessage> &msg) = 0;
+
+private:
+    friend struct ALooperRoster;
+
+    ALooper::handler_id mID;
+
+    void setID(ALooper::handler_id id) {
+        mID = id;
+    }
+
+    DISALLOW_EVIL_CONSTRUCTORS(AHandler);
+};
+
+}  // namespace android
+
+#endif  // A_HANDLER_H_
diff --git a/include/media/stagefright/foundation/ALooper.h b/include/media/stagefright/foundation/ALooper.h
new file mode 100644
index 0000000..69ad837
--- /dev/null
+++ b/include/media/stagefright/foundation/ALooper.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#ifndef A_LOOPER_H_
+
+#define A_LOOPER_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct AHandler;
+struct AMessage;
+
+struct ALooper : public RefBase {
+    typedef int32_t event_id;
+    typedef int32_t handler_id;
+
+    ALooper();
+
+    handler_id registerHandler(const sp<AHandler> &handler);
+    void unregisterHandler(handler_id handlerID);
+
+    status_t start(bool runOnCallingThread = false);
+    status_t stop();
+
+    static int64_t GetNowUs();
+
+protected:
+    virtual ~ALooper();
+
+private:
+    friend struct ALooperRoster;
+
+    struct Event {
+        int64_t mWhenUs;
+        sp<AMessage> mMessage;
+    };
+
+    Mutex mLock;
+    Condition mQueueChangedCondition;
+
+    List<Event> mEventQueue;
+
+    struct LooperThread;
+    sp<LooperThread> mThread;
+    bool mRunningLocally;
+
+    void post(const sp<AMessage> &msg, int64_t delayUs);
+    bool loop();
+
+    DISALLOW_EVIL_CONSTRUCTORS(ALooper);
+};
+
+}  // namespace android
+
+#endif  // A_LOOPER_H_
diff --git a/include/media/stagefright/foundation/ALooperRoster.h b/include/media/stagefright/foundation/ALooperRoster.h
new file mode 100644
index 0000000..1c6869c
--- /dev/null
+++ b/include/media/stagefright/foundation/ALooperRoster.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef A_LOOPER_ROSTER_H_
+
+#define A_LOOPER_ROSTER_H_
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+struct ALooperRoster {
+    ALooperRoster();
+
+    ALooper::handler_id registerHandler(
+            const sp<ALooper> looper, const sp<AHandler> &handler);
+
+    void unregisterHandler(ALooper::handler_id handlerID);
+
+    void postMessage(const sp<AMessage> &msg, int64_t delayUs = 0);
+    void deliverMessage(const sp<AMessage> &msg);
+
+private:
+    struct HandlerInfo {
+        sp<ALooper> mLooper;
+        sp<AHandler> mHandler;
+    };
+
+    Mutex mLock;
+    KeyedVector<ALooper::handler_id, HandlerInfo> mHandlers;
+    ALooper::handler_id mNextHandlerID;
+
+    DISALLOW_EVIL_CONSTRUCTORS(ALooperRoster);
+};
+
+}  // namespace android
+
+#endif  // A_LOOPER_ROSTER_H_
diff --git a/include/media/stagefright/foundation/AMessage.h b/include/media/stagefright/foundation/AMessage.h
new file mode 100644
index 0000000..139c620
--- /dev/null
+++ b/include/media/stagefright/foundation/AMessage.h
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#ifndef A_MESSAGE_H_
+
+#define A_MESSAGE_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct AString;
+
+struct AMessage : public RefBase {
+    AMessage(uint32_t what = 0, ALooper::handler_id target = 0);
+
+    void setWhat(uint32_t what);
+    uint32_t what() const;
+
+    void setTarget(ALooper::handler_id target);
+    ALooper::handler_id target() const;
+
+    void setInt32(const char *name, int32_t value);
+    void setInt64(const char *name, int64_t value);
+    void setSize(const char *name, size_t value);
+    void setFloat(const char *name, float value);
+    void setDouble(const char *name, double value);
+    void setPointer(const char *name, void *value);
+    void setString(const char *name, const char *s, ssize_t len = -1);
+    void setObject(const char *name, const sp<RefBase> &obj);
+    void setMessage(const char *name, const sp<AMessage> &obj);
+
+    bool findInt32(const char *name, int32_t *value) const;
+    bool findInt64(const char *name, int64_t *value) const;
+    bool findSize(const char *name, size_t *value) const;
+    bool findFloat(const char *name, float *value) const;
+    bool findDouble(const char *name, double *value) const;
+    bool findPointer(const char *name, void **value) const;
+    bool findString(const char *name, AString *value) const;
+    bool findObject(const char *name, sp<RefBase> *obj) const;
+    bool findMessage(const char *name, sp<AMessage> *obj) const;
+
+    void post(int64_t delayUs = 0);
+
+    sp<AMessage> dup() const;
+
+protected:
+    virtual ~AMessage();
+
+private:
+    enum Type {
+        kTypeInt32,
+        kTypeInt64,
+        kTypeSize,
+        kTypeFloat,
+        kTypeDouble,
+        kTypePointer,
+        kTypeString,
+        kTypeObject,
+        kTypeMessage,
+    };
+
+    uint32_t mWhat;
+    ALooper::handler_id mTarget;
+
+    struct Item {
+        union {
+            int32_t int32Value;
+            int64_t int64Value;
+            size_t sizeValue;
+            float floatValue;
+            double doubleValue;
+            void *ptrValue;
+            RefBase *refValue;
+            AString *stringValue;
+        } u;
+        const char *mName;
+        Type mType;
+    };
+
+    enum {
+        kMaxNumItems = 16
+    };
+    Item mItems[kMaxNumItems];
+    size_t mNumItems;
+
+    void clear();
+    Item *allocateItem(const char *name);
+    void freeItem(Item *item);
+    const Item *findItem(const char *name, Type type) const;
+
+    DISALLOW_EVIL_CONSTRUCTORS(AMessage);
+};
+
+}  // namespace android
+
+#endif  // A_MESSAGE_H_
diff --git a/include/media/stagefright/foundation/AString.h b/include/media/stagefright/foundation/AString.h
new file mode 100644
index 0000000..55ade64
--- /dev/null
+++ b/include/media/stagefright/foundation/AString.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#ifndef A_STRING_H_
+
+#define A_STRING_H_
+
+#include <sys/types.h>
+
+namespace android {
+
+struct AString {
+    AString();
+    AString(const char *s);
+    AString(const char *s, size_t size);
+    AString(const AString &from);
+    AString(const AString &from, size_t offset, size_t n);
+    ~AString();
+
+    AString &operator=(const AString &from);
+    void setTo(const char *s);
+    void setTo(const char *s, size_t size);
+    void setTo(const AString &from, size_t offset, size_t n);
+
+    size_t size() const;
+    const char *c_str() const;
+
+    bool empty() const;
+
+    void clear();
+    void trim();
+    void erase(size_t start, size_t n);
+
+    void append(char c) { append(&c, 1); }
+    void append(const char *s);
+    void append(const char *s, size_t size);
+    void append(const AString &from);
+    void append(const AString &from, size_t offset, size_t n);
+    void append(int x);
+    void append(unsigned x);
+    void append(long x);
+    void append(unsigned long x);
+    void append(long long x);
+    void append(unsigned long long x);
+    void append(float x);
+    void append(double x);
+    void append(void *x);
+
+    void insert(const AString &from, size_t insertionPos);
+    void insert(const char *from, size_t size, size_t insertionPos);
+
+    ssize_t find(const char *substring, size_t start = 0) const;
+
+    size_t hash() const;
+
+    bool operator==(const AString &other) const;
+    bool operator<(const AString &other) const;
+    bool operator>(const AString &other) const;
+
+    int compare(const AString &other) const;
+
+    bool startsWith(const char *prefix) const;
+
+    void tolower();
+
+private:
+    static const char *kEmptyString;
+
+    char *mData;
+    size_t mSize;
+    size_t mAllocSize;
+
+    void makeMutable();
+};
+
+AString StringPrintf(const char *format, ...);
+
+}  // namespace android
+
+#endif  // A_STRING_H_
+
diff --git a/services/java/com/android/server/status/StatusBarNotification.java b/include/media/stagefright/foundation/base64.h
similarity index 62%
rename from services/java/com/android/server/status/StatusBarNotification.java
rename to include/media/stagefright/foundation/base64.h
index e5773f7..e340b89 100644
--- a/services/java/com/android/server/status/StatusBarNotification.java
+++ b/include/media/stagefright/foundation/base64.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * 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.
@@ -14,14 +14,20 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+#ifndef BASE_64_H_
 
-import android.os.IBinder;
-import android.view.View;
+#define BASE_64_H_
 
-class StatusBarNotification {
-    IBinder key;
-    NotificationData data;
-    View view;
-    View contentView;
-}
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct ABuffer;
+struct AString;
+
+sp<ABuffer> decodeBase64(const AString &s);
+void encodeBase64(const void *data, size_t size, AString *out);
+
+}  // namespace android
+
+#endif  // BASE_64_H_
diff --git a/services/java/com/android/server/status/StatusBarException.java b/include/media/stagefright/foundation/hexdump.h
similarity index 70%
copy from services/java/com/android/server/status/StatusBarException.java
copy to include/media/stagefright/foundation/hexdump.h
index be58f59..f6083a9 100644
--- a/services/java/com/android/server/status/StatusBarException.java
+++ b/include/media/stagefright/foundation/hexdump.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * 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.
@@ -14,10 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+#ifndef HEXDUMP_H_
 
-public class StatusBarException extends RuntimeException {
-    StatusBarException(String msg) {
-        super(msg);
-    }
-}
+#define HEXDUMP_H_
+
+#include <sys/types.h>
+
+namespace android {
+
+void hexdump(const void *_data, size_t size);
+
+}  // namespace android
+
+#endif  // HEXDUMP_H_
diff --git a/include/private/media/AudioEffectShared.h b/include/private/media/AudioEffectShared.h
new file mode 100644
index 0000000..a3a99a4
--- /dev/null
+++ b/include/private/media/AudioEffectShared.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_EFFECTCBASESHARED_H
+#define ANDROID_EFFECTCBASESHARED_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+// Size of buffer used to exchange parameters between application and mediaserver processes.
+#define EFFECT_PARAM_BUFFER_SIZE 1024
+
+
+// Shared memory area used to exchange parameters between application and mediaserver
+// process.
+struct effect_param_cblk_t
+{
+                Mutex       lock;
+    volatile    uint32_t    clientIndex;    // Current read/write index for application
+    volatile    uint32_t    serverIndex;    // Current read/write index for mediaserver
+                uint8_t*    buffer;         // start of parameter buffer
+
+                effect_param_cblk_t()
+                    : lock(Mutex::SHARED), clientIndex(0), serverIndex(0) {}
+};
+
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_EFFECTCBASESHARED_H
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index cd47fdf..1510f87 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -78,7 +78,8 @@
                 uint16_t    bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
                 uint16_t    waitTimeMs;      // Cumulated wait time
 
-                uint32_t    reserved;
+                uint16_t    sendLevel;
+                uint16_t    reserved;
                 // Cache line boundary (32 bytes)
                             audio_track_cblk_t();
                 uint32_t    stepUser(uint32_t frameCount);
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index dcce25e..c11c855 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -122,7 +122,8 @@
     volatile int8_t index[NUM_BUFFER_MAX];
 
     int32_t     identity;       // surface's identity (const)
-    int32_t     reserved32[2];
+    int32_t     token;          // surface's token (for debugging)
+    int32_t     reserved32[1];
     Statistics  stats;
     int32_t     reserved;
     BufferData  buffers[NUM_BUFFER_MAX];     // 960 bytes
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 3271cfd..dd44aa5 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -85,9 +85,12 @@
     /* create connection with surface flinger, requires
      * ACCESS_SURFACE_FLINGER permission
      */
-
     virtual sp<ISurfaceComposerClient> createConnection() = 0;
 
+    /* create a client connection with surface flinger
+     */
+    virtual sp<ISurfaceComposerClient> createClientConnection() = 0;
+
     /* retrieve the control block */
     virtual sp<IMemoryHeap> getCblk() const = 0;
 
@@ -123,6 +126,7 @@
         // Java by ActivityManagerService.
         BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
         CREATE_CONNECTION,
+        CREATE_CLIENT_CONNECTION,
         GET_CBLK,
         OPEN_GLOBAL_TRANSACTION,
         CLOSE_GLOBAL_TRANSACTION,
diff --git a/include/surfaceflinger/ISurfaceComposerClient.h b/include/surfaceflinger/ISurfaceComposerClient.h
index b2a4766..a1e9e04 100644
--- a/include/surfaceflinger/ISurfaceComposerClient.h
+++ b/include/surfaceflinger/ISurfaceComposerClient.h
@@ -58,6 +58,7 @@
     };
 
     virtual sp<IMemoryHeap> getControlBlock() const = 0;
+    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const = 0;
 
     /*
      * Requires ACCESS_SURFACE_FLINGER permission
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 2957970..ac01ce5 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -145,15 +145,13 @@
         uint32_t    reserved[2];
     };
 
-    Surface(const Parcel& data);
+    static sp<Surface> readFromParcel(
+            const Parcel& data, const sp<Surface>& other);
 
     static bool isValid(const sp<Surface>& surface) {
         return (surface != 0) && surface->isValid();
     }
 
-    static bool isSameSurface(
-            const sp<Surface>& lhs, const sp<Surface>& rhs);
-
     bool        isValid();
     SurfaceID   ID() const          { return mToken; }
     uint32_t    getFlags() const    { return mFlags; }
@@ -191,6 +189,7 @@
     Surface(const Surface& rhs);
 
     Surface(const sp<SurfaceControl>& control);
+    Surface(const Parcel& data, const sp<IBinder>& ref);
     ~Surface();
 
 
@@ -229,7 +228,6 @@
      */
     void init();
     status_t validate() const;
-    status_t initCheck() const;
     sp<ISurface> getISurface() const;
 
     inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
@@ -264,15 +262,15 @@
     };
 
     // constants
-    sp<SurfaceClient>           mClient;
+    GraphicBufferMapper&        mBufferMapper;
+    SurfaceClient&              mClient;
+    SharedBufferClient*         mSharedBufferClient;
+    status_t                    mInitCheck;
     sp<ISurface>                mSurface;
     SurfaceID                   mToken;
     uint32_t                    mIdentity;
     PixelFormat                 mFormat;
     uint32_t                    mFlags;
-    GraphicBufferMapper&        mBufferMapper;
-    SharedBufferClient*         mSharedBufferClient;
-    status_t                    mInitCheck;
 
     // protected by mSurfaceLock
     Rect                        mSwapRectangle;
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index 8e28a81..8773d71 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -22,8 +22,9 @@
 
 #include <binder/IBinder.h>
 
-#include <utils/SortedVector.h>
 #include <utils/RefBase.h>
+#include <utils/Singleton.h>
+#include <utils/SortedVector.h>
 #include <utils/threads.h>
 
 #include <ui/PixelFormat.h>
@@ -39,6 +40,22 @@
 class SharedClient;
 class ISurfaceComposer;
 class DisplayInfo;
+class surface_flinger_cblk_t;
+
+// ---------------------------------------------------------------------------
+
+class ComposerService : public Singleton<ComposerService>
+{
+    // these are constants
+    sp<ISurfaceComposer> mComposerService;
+    sp<IMemoryHeap> mServerCblkMemory;
+    surface_flinger_cblk_t volatile* mServerCblk;
+    ComposerService();
+    friend class Singleton<ComposerService>;
+public:
+    static sp<ISurfaceComposer> getComposerService();
+    static surface_flinger_cblk_t const volatile * getControlBlock();
+};
 
 // ---------------------------------------------------------------------------
 
@@ -153,25 +170,6 @@
 };
 
 // ---------------------------------------------------------------------------
-
-class SurfaceClient : public RefBase
-{
-    // all these attributes are constants
-    status_t                    mStatus;
-    SharedClient*               mControl;
-    sp<IMemoryHeap>             mControlMemory;
-    sp<IBinder>                 mConnection;
-    sp<ISurfaceComposer>        mComposerService;
-    void init(const sp<IBinder>& conn);
-public:
-    explicit SurfaceClient(const sp<IBinder>& conn);
-    explicit SurfaceClient(const sp<SurfaceComposerClient>& client);
-    status_t initCheck() const;
-    SharedClient* getSharedClient() const;
-    void signalServer() const;
-};
-
-// ---------------------------------------------------------------------------
 }; // namespace android
 
 #endif // ANDROID_SF_SURFACE_COMPOSER_CLIENT_H
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index e72b6b3..a3e85a9 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -93,10 +93,8 @@
     
     void setIndex(int index);
     int getIndex() const;
-    void setVerticalStride(uint32_t vstride);
-    uint32_t getVerticalStride() const;
 
-protected:
+private:
     virtual ~GraphicBuffer();
 
     enum {
@@ -105,8 +103,12 @@
         ownData   = 2,
     };
 
-    inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
-    inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
+    inline const GraphicBufferMapper& getBufferMapper() const {
+        return mBufferMapper;
+    }
+    inline GraphicBufferMapper& getBufferMapper() {
+        return mBufferMapper;
+    }
     uint8_t mOwner;
 
 private:
@@ -134,7 +136,6 @@
 
     GraphicBufferMapper& mBufferMapper;
     ssize_t mInitCheck;
-    uint32_t mVStride;
     int mIndex;
 };
 
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
index 870c0b8..22ecc54 100644
--- a/libs/audioflinger/Android.mk
+++ b/libs/audioflinger/Android.mk
@@ -87,7 +87,8 @@
     libutils \
     libbinder \
     libmedia \
-    libhardware_legacy
+    libhardware_legacy \
+    libeffects
 
 ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
   LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 3b38d83..1860793 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -37,7 +37,7 @@
 #include <media/AudioRecord.h>
 
 #include <private/media/AudioTrackShared.h>
-
+#include <private/media/AudioEffectShared.h>
 #include <hardware_legacy/AudioHardwareInterface.h>
 
 #include "AudioMixer.h"
@@ -51,6 +51,8 @@
 #include "lifevibes.h"
 #endif
 
+#include <media/EffectFactoryApi.h>
+
 // ----------------------------------------------------------------------------
 // the sim build doesn't have gettid
 
@@ -67,6 +69,7 @@
 
 //static const nsecs_t kStandbyTimeInNsecs = seconds(3);
 static const float MAX_GAIN = 4096.0f;
+static const float MAX_GAIN_INT = 0x1000;
 
 // retry counts for buffer fill timeout
 // 50 * ~20msecs = 1 second
@@ -123,7 +126,7 @@
 
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(),
-        mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextThreadId(0)
+        mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)
 {
     mHardwareStatus = AUDIO_HW_IDLE;
 
@@ -282,6 +285,7 @@
         uint32_t flags,
         const sp<IMemory>& sharedBuffer,
         int output,
+        int *sessionId,
         status_t *status)
 {
     sp<PlaybackThread::Track> track;
@@ -289,6 +293,7 @@
     sp<Client> client;
     wp<Client> wclient;
     status_t lStatus;
+    int lSessionId;
 
     if (streamType >= AudioSystem::NUM_STREAM_TYPES) {
         LOGE("invalid stream type");
@@ -313,8 +318,23 @@
             client = new Client(this, pid);
             mClients.add(pid, client);
         }
+
+        // If no audio session id is provided, create one here
+        // TODO: enforce same stream type for all tracks in same audio session?
+        // TODO: prevent same audio session on different output threads
+        LOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId);
+        if (sessionId != NULL && *sessionId != 0) {
+            lSessionId = *sessionId;
+        } else {
+            lSessionId = nextUniqueId();
+            if (sessionId != NULL) {
+                *sessionId = lSessionId;
+            }
+        }
+        LOGV("createTrack() lSessionId: %d", lSessionId);
+
         track = thread->createTrack_l(client, streamType, sampleRate, format,
-                channelCount, frameCount, sharedBuffer, &lStatus);
+                channelCount, frameCount, sharedBuffer, lSessionId, &lStatus);
     }
     if (lStatus == NO_ERROR) {
         trackHandle = new TrackHandle(track);
@@ -940,10 +960,11 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id)
+AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
     :   ThreadBase(audioFlinger, id),
         mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output),
-        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
+        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
+        mDevice(device)
 {
     readOutputParameters();
 
@@ -965,6 +986,7 @@
 {
     dumpInternals(fd, args);
     dumpTracks(fd, args);
+    dumpEffectChains(fd, args);
     return NO_ERROR;
 }
 
@@ -976,7 +998,7 @@
 
     snprintf(buffer, SIZE, "Output thread %p tracks\n", this);
     result.append(buffer);
-    result.append("   Name Clien Typ Fmt Chn Buf  S M F SRate  LeftV RighV Serv     User\n");
+    result.append("   Name  Clien Typ Fmt Chn Session Buf  S M F SRate LeftV RighV  Serv       User       Main buf   Aux Buf\n");
     for (size_t i = 0; i < mTracks.size(); ++i) {
         sp<Track> track = mTracks[i];
         if (track != 0) {
@@ -987,7 +1009,7 @@
 
     snprintf(buffer, SIZE, "Output thread %p active tracks\n", this);
     result.append(buffer);
-    result.append("   Name Clien Typ Fmt Chn Buf  S M F SRate  LeftV RighV Serv     User\n");
+    result.append("   Name  Clien Typ Fmt Chn Session Buf  S M F SRate LeftV RighV  Serv       User       Main buf   Aux Buf\n");
     for (size_t i = 0; i < mActiveTracks.size(); ++i) {
         wp<Track> wTrack = mActiveTracks[i];
         if (wTrack != 0) {
@@ -1002,6 +1024,24 @@
     return NO_ERROR;
 }
 
+status_t AudioFlinger::PlaybackThread::dumpEffectChains(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "\n- %d Effect Chains:\n", mEffectChains.size());
+    write(fd, buffer, strlen(buffer));
+
+    for (size_t i = 0; i < mEffectChains.size(); ++i) {
+        sp<EffectChain> chain = mEffectChains[i];
+        if (chain != 0) {
+            chain->dump(fd, args);
+        }
+    }
+    return NO_ERROR;
+}
+
 status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
@@ -1020,6 +1060,8 @@
     result.append(buffer);
     snprintf(buffer, SIZE, "suspend count: %d\n", mSuspended);
     result.append(buffer);
+    snprintf(buffer, SIZE, "mix buffer : %p\n", mMixBuffer);
+    result.append(buffer);
     write(fd, result.string(), result.size());
 
     dumpBase(fd, args);
@@ -1057,6 +1099,7 @@
         int channelCount,
         int frameCount,
         const sp<IMemory>& sharedBuffer,
+        int sessionId,
         status_t *status)
 {
     sp<Track> track;
@@ -1087,12 +1130,18 @@
     { // scope for mLock
         Mutex::Autolock _l(mLock);
         track = new Track(this, client, streamType, sampleRate, format,
-                channelCount, frameCount, sharedBuffer);
+                channelCount, frameCount, sharedBuffer, sessionId);
         if (track->getCblk() == NULL || track->name() < 0) {
             lStatus = NO_MEMORY;
             goto Exit;
         }
         mTracks.add(track);
+
+        sp<EffectChain> chain = getEffectChain_l(sessionId);
+        if (chain != 0) {
+            LOGV("createTrack_l() setting main buffer %p", chain->inBuffer());
+            track->setMainBuffer(chain->inBuffer());
+        }
     }
     lStatus = NO_ERROR;
 
@@ -1209,6 +1258,14 @@
         track->mFillingUpStatus = Track::FS_FILLING;
         track->mResetDone = false;
         mActiveTracks.add(track);
+        if (track->mainBuffer() != mMixBuffer) {
+            sp<EffectChain> chain = getEffectChain_l(track->sessionId());
+            if (chain != 0) {
+                LOGV("addTrack_l() starting track on chain %p for session %d", chain.get(), track->sessionId());
+                chain->startTrack();
+            }
+        }
+
         status = NO_ERROR;
     }
 
@@ -1271,9 +1328,11 @@
 
     // FIXME - Current mixer implementation only supports stereo output: Always
     // Allocate a stereo buffer even if HW output is mono.
-    if (mMixBuffer != NULL) delete mMixBuffer;
+    if (mMixBuffer != NULL) delete[] mMixBuffer;
     mMixBuffer = new int16_t[mFrameCount * 2];
     memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
+
+    //TODO handle effects reconfig
 }
 
 status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames)
@@ -1289,10 +1348,47 @@
     return mOutput->getRenderPosition(dspFrames);
 }
 
+bool AudioFlinger::PlaybackThread::hasAudioSession(int sessionId)
+{
+    Mutex::Autolock _l(mLock);
+    if (getEffectChain_l(sessionId) != 0) {
+        return true;
+    }
+
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        sp<Track> track = mTracks[i];
+        if (sessionId == track->sessionId()) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain(int sessionId)
+{
+    Mutex::Autolock _l(mLock);
+    return getEffectChain_l(sessionId);
+}
+
+sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain_l(int sessionId)
+{
+    sp<EffectChain> chain;
+
+    size_t size = mEffectChains.size();
+    for (size_t i = 0; i < size; i++) {
+        if (mEffectChains[i]->sessionId() == sessionId) {
+            chain = mEffectChains[i];
+            break;
+        }
+    }
+    return chain;
+}
+
 // ----------------------------------------------------------------------------
 
-AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id)
-    :   PlaybackThread(audioFlinger, output, id),
+AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
+    :   PlaybackThread(audioFlinger, output, id, device),
         mAudioMixer(0)
 {
     mType = PlaybackThread::MIXER;
@@ -1311,7 +1407,6 @@
 
 bool AudioFlinger::MixerThread::threadLoop()
 {
-    int16_t* curBuf = mMixBuffer;
     Vector< sp<Track> > tracksToRemove;
     uint32_t mixerStatus = MIXER_IDLE;
     nsecs_t standbyTime = systemTime();
@@ -1324,6 +1419,7 @@
     uint32_t activeSleepTime = activeSleepTimeUs();
     uint32_t idleSleepTime = idleSleepTimeUs();
     uint32_t sleepTime = idleSleepTime;
+    Vector< sp<EffectChain> > effectChains;
 
     while (!exitPending())
     {
@@ -1382,13 +1478,20 @@
             }
 
             mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove);
+
+            // prevent any changes in effect chain list and in each effect chain
+            // during mixing and effect process as the audio buffers could be deleted
+            // or modified if an effect is created or deleted
+            effectChains = mEffectChains;
+            lockEffectChains_l();
        }
 
         if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
             // mix buffers...
-            mAudioMixer->process(curBuf);
+            mAudioMixer->process();
             sleepTime = 0;
             standbyTime = systemTime() + kStandbyTimeInNsecs;
+            //TODO: delay standby when effects have a tail
         } else {
             // If no tracks are ready, sleep once for the duration of an output
             // buffer size, then write 0s to the output
@@ -1400,10 +1503,11 @@
                 }
             } else if (mBytesWritten != 0 ||
                        (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) {
-                memset (curBuf, 0, mixBufferSize);
+                memset (mMixBuffer, 0, mixBufferSize);
                 sleepTime = 0;
                 LOGV_IF((mBytesWritten == 0 && (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start");
             }
+            // TODO add standby time extension fct of effect tail
         }
 
         if (mSuspended) {
@@ -1411,16 +1515,22 @@
         }
         // sleepTime == 0 means we must write to audio hardware
         if (sleepTime == 0) {
-            mLastWriteTime = systemTime();
-            mInWrite = true;
-            mBytesWritten += mixBufferSize;
+             for (size_t i = 0; i < effectChains.size(); i ++) {
+                 effectChains[i]->process_l();
+             }
+             // enable changes in effect chain
+             unlockEffectChains();
 #ifdef LVMX
             int audioOutputType = LifeVibes::getMixerType(mId, mType);
             if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) {
-               LifeVibes::process(audioOutputType, curBuf, mixBufferSize);
+               LifeVibes::process(audioOutputType, mMixBuffer, mixBufferSize);
             }
 #endif
-            int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize);
+            mLastWriteTime = systemTime();
+            mInWrite = true;
+            mBytesWritten += mixBufferSize;
+
+            int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize);
             if (bytesWritten < 0) mBytesWritten -= mixBufferSize;
             mNumWrites++;
             mInWrite = false;
@@ -1439,6 +1549,8 @@
             }
             mStandby = false;
         } else {
+            // enable changes in effect chain
+            unlockEffectChains();
             usleep(sleepTime);
         }
 
@@ -1446,6 +1558,10 @@
         // since we can't guarantee the destructors won't acquire that
         // same lock.
         tracksToRemove.clear();
+
+        // Effect chains will be actually deleted here if they were removed from
+        // mEffectChains list during mixing or effects processing
+        effectChains.clear();
     }
 
     if (!mStandby) {
@@ -1463,6 +1579,8 @@
     uint32_t mixerStatus = MIXER_IDLE;
     // find out which tracks need to be processed
     size_t count = activeTracks.size();
+    size_t mixedTracks = 0;
+    size_t tracksWithEffect = 0;
 
     float masterVolume = mMasterVolume;
     bool  masterMute = mMasterMute;
@@ -1485,6 +1603,14 @@
         LifeVibes::computeVolumes(audioOutputType, activeTypes, tracksConnectedChanged, stateChanged, masterVolume, masterMute);
     }
 #endif
+    // Delegate master volume control to effect in output mix effect chain if needed
+    sp<EffectChain> chain = getEffectChain_l(0);
+    if (chain != 0) {
+        uint32_t v = (uint32_t)(masterVolume * (1 << 24));
+        chain->setVolume(&v, &v);
+        masterVolume = (float)((v + (1 << 23)) >> 24);
+        chain.clear();
+    }
 
     for (size_t i=0 ; i<count ; i++) {
         sp<Track> t = activeTracks[i].promote();
@@ -1501,11 +1627,42 @@
         {
             //LOGV("track %d u=%08x, s=%08x [OK] on thread %p", track->name(), cblk->user, cblk->server, this);
 
+            mixedTracks++;
+
+            // track->mainBuffer() != mMixBuffer means there is an effect chain
+            // connected to the track
+            chain.clear();
+            if (track->mainBuffer() != mMixBuffer) {
+                chain = getEffectChain_l(track->sessionId());
+                // Delegate volume control to effect in track effect chain if needed
+                if (chain != 0) {
+                    tracksWithEffect++;
+                } else {
+                    LOGW("prepareTracks_l(): track %08x attached to effect but no chain found on session %d",
+                            track->name(), track->sessionId());
+                }
+            }
+
+
+            int param = AudioMixer::VOLUME;
+            if (track->mFillingUpStatus == Track::FS_FILLED) {
+                // no ramp for the first volume setting
+                track->mFillingUpStatus = Track::FS_ACTIVE;
+                if (track->mState == TrackBase::RESUMING) {
+                    track->mState = TrackBase::ACTIVE;
+                    param = AudioMixer::RAMP_VOLUME;
+                }
+            } else if (cblk->server != 0) {
+                // If the track is stopped before the first frame was mixed,
+                // do not apply ramp
+                param = AudioMixer::RAMP_VOLUME;
+            }
+
             // compute volume for this track
-            int16_t left, right;
+            int16_t left, right, aux;
             if (track->isMuted() || masterMute || track->isPausing() ||
                 mStreamTypes[track->type()].mute) {
-                left = right = 0;
+                left = right = aux = 0;
                 if (track->isPausing()) {
                     track->setPaused();
                 }
@@ -1524,31 +1681,28 @@
                 }
 #endif
                 float v = masterVolume * typeVolume;
-                float v_clamped = v * cblk->volume[0];
-                if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
-                left = int16_t(v_clamped);
-                v_clamped = v * cblk->volume[1];
-                if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
-                right = int16_t(v_clamped);
-            }
+                uint32_t vl = (uint32_t)(v * cblk->volume[0]) << 12;
+                uint32_t vr = (uint32_t)(v * cblk->volume[1]) << 12;
 
-            // XXX: these things DON'T need to be done each time
-            mAudioMixer->setBufferProvider(track);
-            mAudioMixer->enable(AudioMixer::MIXING);
-
-            int param = AudioMixer::VOLUME;
-            if (track->mFillingUpStatus == Track::FS_FILLED) {
-                // no ramp for the first volume setting
-                track->mFillingUpStatus = Track::FS_ACTIVE;
-                if (track->mState == TrackBase::RESUMING) {
-                    track->mState = TrackBase::ACTIVE;
-                    param = AudioMixer::RAMP_VOLUME;
+                // Delegate volume control to effect in track effect chain if needed
+                if (chain != 0 && chain->setVolume(&vl, &vr)) {
+                    // Do not ramp volume is volume is controlled by effect
+                    param = AudioMixer::VOLUME;
                 }
-            } else if (cblk->server != 0) {
-                // If the track is stopped before the first frame was mixed,
-                // do not apply ramp
-                param = AudioMixer::RAMP_VOLUME;
+
+                // Convert volumes from 8.24 to 4.12 format
+                uint32_t v_clamped = (vl + (1 << 11)) >> 12;
+                if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
+                left = int16_t(v_clamped);
+                v_clamped = (vr + (1 << 11)) >> 12;
+                if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
+                right = int16_t(v_clamped);
+
+                v_clamped = (uint32_t)(v * cblk->sendLevel);
+                if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
+                aux = int16_t(v_clamped);
             }
+
 #ifdef LVMX
             if ( tracksConnectedChanged || stateChanged )
             {
@@ -1556,18 +1710,30 @@
                  param = AudioMixer::VOLUME;
             }
 #endif
-            mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
-            mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
+
+            // XXX: these things DON'T need to be done each time
+            mAudioMixer->setBufferProvider(track);
+            mAudioMixer->enable(AudioMixer::MIXING);
+
+            mAudioMixer->setParameter(param, AudioMixer::VOLUME0, (void *)left);
+            mAudioMixer->setParameter(param, AudioMixer::VOLUME1, (void *)right);
+            mAudioMixer->setParameter(param, AudioMixer::AUXLEVEL, (void *)aux);
             mAudioMixer->setParameter(
                 AudioMixer::TRACK,
-                AudioMixer::FORMAT, track->format());
+                AudioMixer::FORMAT, (void *)track->format());
             mAudioMixer->setParameter(
                 AudioMixer::TRACK,
-                AudioMixer::CHANNEL_COUNT, track->channelCount());
+                AudioMixer::CHANNEL_COUNT, (void *)track->channelCount());
             mAudioMixer->setParameter(
                 AudioMixer::RESAMPLE,
                 AudioMixer::SAMPLE_RATE,
-                int(cblk->sampleRate));
+                (void *)(cblk->sampleRate));
+            mAudioMixer->setParameter(
+                AudioMixer::TRACK,
+                AudioMixer::MAIN_BUFFER, (void *)track->mainBuffer());
+            mAudioMixer->setParameter(
+                AudioMixer::TRACK,
+                AudioMixer::AUX_BUFFER, (void *)track->auxBuffer());
 
             // reset retry count
             track->mRetryCount = kMaxTrackRetries;
@@ -1581,7 +1747,6 @@
                 // We have consumed all the buffers of this track.
                 // Remove it from the list of active tracks.
                 tracksToRemove->add(track);
-                mAudioMixer->disable(AudioMixer::MIXING);
             } else {
                 // No buffers for this track. Give it a few chances to
                 // fill a buffer, then remove it from active list.
@@ -1591,9 +1756,8 @@
                 } else if (mixerStatus != MIXER_TRACKS_READY) {
                     mixerStatus = MIXER_TRACKS_ENABLED;
                 }
-
-                mAudioMixer->disable(AudioMixer::MIXING);
             }
+            mAudioMixer->disable(AudioMixer::MIXING);
         }
     }
 
@@ -1603,6 +1767,13 @@
         for (size_t i=0 ; i<count ; i++) {
             const sp<Track>& track = tracksToRemove->itemAt(i);
             mActiveTracks.remove(track);
+            if (track->mainBuffer() != mMixBuffer) {
+                chain = getEffectChain_l(track->sessionId());
+                if (chain != 0) {
+                    LOGV("stopping track on chain %p for session Id: %d", chain.get(), track->sessionId());
+                    chain->stopTrack();
+                }
+            }
             if (track->isTerminated()) {
                 mTracks.remove(track);
                 deleteTrackName_l(track->mName);
@@ -1610,6 +1781,13 @@
         }
     }
 
+    // mix buffer must be cleared if all tracks are connected to an
+    // effect chain as in this case the mixer will not write to
+    // mix buffer and track effects will accumulate into it
+    if (mixedTracks != 0 && mixedTracks == tracksWithEffect) {
+        memset(mMixBuffer, 0, mFrameCount * mChannelCount * sizeof(int16_t));
+    }
+
     return mixerStatus;
 }
 
@@ -1681,6 +1859,15 @@
                 reconfig = true;
             }
         }
+        if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+            // forward device change to effects that have requested to be
+            // aware of attached audio device.
+            mDevice = (uint32_t)value;
+            for (size_t i = 0; i < mEffectChains.size(); i++) {
+                mEffectChains[i]->setDevice(mDevice);
+            }
+        }
+
         if (status == NO_ERROR) {
             status = mOutput->setParameters(keyValuePair);
             if (!mStandby && status == INVALID_OPERATION) {
@@ -1740,9 +1927,8 @@
 }
 
 // ----------------------------------------------------------------------------
-AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id)
-    :   PlaybackThread(audioFlinger, output, id),
-    mLeftVolume (1.0), mRightVolume(1.0)
+AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
+    :   PlaybackThread(audioFlinger, output, id, device)
 {
     mType = PlaybackThread::DIRECT;
 }
@@ -1752,6 +1938,102 @@
 }
 
 
+static inline int16_t clamp16(int32_t sample)
+{
+    if ((sample>>15) ^ (sample>>31))
+        sample = 0x7FFF ^ (sample>>31);
+    return sample;
+}
+
+static inline
+int32_t mul(int16_t in, int16_t v)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    asm( "smulbb %[out], %[in], %[v] \n"
+         : [out]"=r"(out)
+         : [in]"%r"(in), [v]"r"(v)
+         : );
+    return out;
+#else
+    return in * int32_t(v);
+#endif
+}
+
+void AudioFlinger::DirectOutputThread::applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp)
+{
+    // Do not apply volume on compressed audio
+    if (!AudioSystem::isLinearPCM(mFormat)) {
+        return;
+    }
+
+    // convert to signed 16 bit before volume calculation
+    if (mFormat == AudioSystem::PCM_8_BIT) {
+        size_t count = mFrameCount * mChannelCount;
+        uint8_t *src = (uint8_t *)mMixBuffer + count-1;
+        int16_t *dst = mMixBuffer + count-1;
+        while(count--) {
+            *dst-- = (int16_t)(*src--^0x80) << 8;
+        }
+    }
+
+    size_t frameCount = mFrameCount;
+    int16_t *out = mMixBuffer;
+    if (ramp) {
+        if (mChannelCount == 1) {
+            int32_t d = ((int32_t)leftVol - (int32_t)mLeftVolShort) << 16;
+            int32_t vlInc = d / (int32_t)frameCount;
+            int32_t vl = ((int32_t)mLeftVolShort << 16);
+            do {
+                out[0] = clamp16(mul(out[0], vl >> 16) >> 12);
+                out++;
+                vl += vlInc;
+            } while (--frameCount);
+
+        } else {
+            int32_t d = ((int32_t)leftVol - (int32_t)mLeftVolShort) << 16;
+            int32_t vlInc = d / (int32_t)frameCount;
+            d = ((int32_t)rightVol - (int32_t)mRightVolShort) << 16;
+            int32_t vrInc = d / (int32_t)frameCount;
+            int32_t vl = ((int32_t)mLeftVolShort << 16);
+            int32_t vr = ((int32_t)mRightVolShort << 16);
+            do {
+                out[0] = clamp16(mul(out[0], vl >> 16) >> 12);
+                out[1] = clamp16(mul(out[1], vr >> 16) >> 12);
+                out += 2;
+                vl += vlInc;
+                vr += vrInc;
+            } while (--frameCount);
+        }
+    } else {
+        if (mChannelCount == 1) {
+            do {
+                out[0] = clamp16(mul(out[0], leftVol) >> 12);
+                out++;
+            } while (--frameCount);
+        } else {
+            do {
+                out[0] = clamp16(mul(out[0], leftVol) >> 12);
+                out[1] = clamp16(mul(out[1], rightVol) >> 12);
+                out += 2;
+            } while (--frameCount);
+        }
+    }
+
+    // convert back to unsigned 8 bit after volume calculation
+    if (mFormat == AudioSystem::PCM_8_BIT) {
+        size_t count = mFrameCount * mChannelCount;
+        int16_t *src = mMixBuffer;
+        uint8_t *dst = (uint8_t *)mMixBuffer;
+        while(count--) {
+            *dst++ = (uint8_t)(((int32_t)*src++ + (1<<7)) >> 8)^0x80;
+        }
+    }
+
+    mLeftVolShort = leftVol;
+    mRightVolShort = rightVol;
+}
+
 bool AudioFlinger::DirectOutputThread::threadLoop()
 {
     uint32_t mixerStatus = MIXER_IDLE;
@@ -1770,6 +2052,11 @@
 
     while (!exitPending())
     {
+        bool rampVolume;
+        uint16_t leftVol;
+        uint16_t rightVol;
+        Vector< sp<EffectChain> > effectChains;
+
         processConfigEvents();
 
         mixerStatus = MIXER_IDLE;
@@ -1821,6 +2108,8 @@
                 }
             }
 
+            effectChains = mEffectChains;
+
             // find out which tracks need to be processed
             if (mActiveTracks.size() != 0) {
                 sp<Track> t = mActiveTracks[0].promote();
@@ -1836,6 +2125,19 @@
                 {
                     //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
 
+                    if (track->mFillingUpStatus == Track::FS_FILLED) {
+                        track->mFillingUpStatus = Track::FS_ACTIVE;
+                        mLeftVolFloat = mRightVolFloat = 0;
+                        mLeftVolShort = mRightVolShort = 0;
+                        if (track->mState == TrackBase::RESUMING) {
+                            track->mState = TrackBase::ACTIVE;
+                            rampVolume = true;
+                        }
+                    } else if (cblk->server != 0) {
+                        // If the track is stopped before the first frame was mixed,
+                        // do not apply ramp
+                        rampVolume = true;
+                    }
                     // compute volume for this track
                     float left, right;
                     if (track->isMuted() || mMasterMute || track->isPausing() ||
@@ -1855,17 +2157,42 @@
                         right = v_clamped/MAX_GAIN;
                     }
 
-                    if (left != mLeftVolume || right != mRightVolume) {
-                        mOutput->setVolume(left, right);
-                        left = mLeftVolume;
-                        right = mRightVolume;
-                    }
+                    if (left != mLeftVolFloat || right != mRightVolFloat) {
+                        mLeftVolFloat = left;
+                        mRightVolFloat = right;
 
-                    if (track->mFillingUpStatus == Track::FS_FILLED) {
-                        track->mFillingUpStatus = Track::FS_ACTIVE;
-                        if (track->mState == TrackBase::RESUMING) {
-                            track->mState = TrackBase::ACTIVE;
+                        // If audio HAL implements volume control,
+                        // force software volume to nominal value
+                        if (mOutput->setVolume(left, right) == NO_ERROR) {
+                            left = 1.0f;
+                            right = 1.0f;
                         }
+
+                        // Convert volumes from float to 8.24
+                        uint32_t vl = (uint32_t)(left * (1 << 24));
+                        uint32_t vr = (uint32_t)(right * (1 << 24));
+
+                        // Delegate volume control to effect in track effect chain if needed
+                        // only one effect chain can be present on DirectOutputThread, so if
+                        // there is one, the track is connected to it
+                        if (!effectChains.isEmpty()) {
+                            // Do not ramp volume is volume is controlled by effect
+                            if(effectChains[0]->setVolume(&vl, &vr)) {
+                                rampVolume = false;
+                            }
+                        }
+
+                        // Convert volumes from 8.24 to 4.12 format
+                        uint32_t v_clamped = (vl + (1 << 11)) >> 12;
+                        if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
+                        leftVol = (uint16_t)v_clamped;
+                        v_clamped = (vr + (1 << 11)) >> 12;
+                        if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
+                        rightVol = (uint16_t)v_clamped;
+                    } else {
+                        leftVol = mLeftVolShort;
+                        rightVol = mRightVolShort;
+                        rampVolume = false;
                     }
 
                     // reset retry count
@@ -1897,11 +2224,17 @@
             // remove all the tracks that need to be...
             if (UNLIKELY(trackToRemove != 0)) {
                 mActiveTracks.remove(trackToRemove);
+                if (!effectChains.isEmpty()) {
+                    LOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(), trackToRemove->sessionId());
+                    effectChains[0]->stopTrack();
+                }
                 if (trackToRemove->isTerminated()) {
                     mTracks.remove(trackToRemove);
                     deleteTrackName_l(trackToRemove->mName);
                 }
             }
+
+            lockEffectChains_l();
        }
 
         if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
@@ -1909,7 +2242,7 @@
             size_t frameCount = mFrameCount;
             curBuf = (int8_t *)mMixBuffer;
             // output audio to hardware
-            while(frameCount) {
+            while (frameCount) {
                 buffer.frameCount = frameCount;
                 activeTrack->getNextBuffer(&buffer);
                 if (UNLIKELY(buffer.raw == 0)) {
@@ -1941,6 +2274,14 @@
         }
         // sleepTime == 0 means we must write to audio hardware
         if (sleepTime == 0) {
+            if (mixerStatus == MIXER_TRACKS_READY) {
+                applyVolume(leftVol, rightVol, rampVolume);
+            }
+            for (size_t i = 0; i < effectChains.size(); i ++) {
+                effectChains[i]->process_l();
+            }
+            unlockEffectChains();
+
             mLastWriteTime = systemTime();
             mInWrite = true;
             mBytesWritten += mixBufferSize;
@@ -1950,6 +2291,7 @@
             mInWrite = false;
             mStandby = false;
         } else {
+            unlockEffectChains();
             usleep(sleepTime);
         }
 
@@ -1958,6 +2300,10 @@
         // same lock.
         trackToRemove.clear();
         activeTrack.clear();
+
+        // Effect chains will be actually deleted here if they were removed from
+        // mEffectChains list during mixing or effects processing
+        effectChains.clear();
     }
 
     if (!mStandby) {
@@ -2048,7 +2394,7 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, int id)
-    :   MixerThread(audioFlinger, mainThread->getOutput(), id), mWaitTimeMs(UINT_MAX)
+    :   MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->device()), mWaitTimeMs(UINT_MAX)
 {
     mType = PlaybackThread::DUPLICATING;
     addOutputTrack(mainThread);
@@ -2064,7 +2410,6 @@
 
 bool AudioFlinger::DuplicatingThread::threadLoop()
 {
-    int16_t* curBuf = mMixBuffer;
     Vector< sp<Track> > tracksToRemove;
     uint32_t mixerStatus = MIXER_IDLE;
     nsecs_t standbyTime = systemTime();
@@ -2074,6 +2419,7 @@
     uint32_t activeSleepTime = activeSleepTimeUs();
     uint32_t idleSleepTime = idleSleepTimeUs();
     uint32_t sleepTime = idleSleepTime;
+    Vector< sp<EffectChain> > effectChains;
 
     while (!exitPending())
     {
@@ -2134,14 +2480,20 @@
             }
 
             mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove);
+
+            // prevent any changes in effect chain list and in each effect chain
+            // during mixing and effect process as the audio buffers could be deleted
+            // or modified if an effect is created or deleted
+            effectChains = mEffectChains;
+            lockEffectChains_l();
         }
 
         if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
             // mix buffers...
             if (outputsReady(outputTracks)) {
-                mAudioMixer->process(curBuf);
+                mAudioMixer->process();
             } else {
-                memset(curBuf, 0, mixBufferSize);
+                memset(mMixBuffer, 0, mixBufferSize);
             }
             sleepTime = 0;
             writeFrames = mFrameCount;
@@ -2158,6 +2510,7 @@
                     if (outputTracks[i]->isActive()) {
                         sleepTime = 0;
                         writeFrames = 0;
+                        memset(mMixBuffer, 0, mixBufferSize);
                         break;
                     }
                 }
@@ -2169,13 +2522,21 @@
         }
         // sleepTime == 0 means we must write to audio hardware
         if (sleepTime == 0) {
+            for (size_t i = 0; i < effectChains.size(); i ++) {
+                effectChains[i]->process_l();
+            }
+            // enable changes in effect chain
+            unlockEffectChains();
+
             standbyTime = systemTime() + kStandbyTimeInNsecs;
             for (size_t i = 0; i < outputTracks.size(); i++) {
-                outputTracks[i]->write(curBuf, writeFrames);
+                outputTracks[i]->write(mMixBuffer, writeFrames);
             }
             mStandby = false;
             mBytesWritten += mixBufferSize;
         } else {
+            // enable changes in effect chain
+            unlockEffectChains();
             usleep(sleepTime);
         }
 
@@ -2184,6 +2545,10 @@
         // same lock.
         tracksToRemove.clear();
         outputTracks.clear();
+
+        // Effect chains will be actually deleted here if they were removed from
+        // mEffectChains list during mixing or effects processing
+        effectChains.clear();
     }
 
     return false;
@@ -2268,7 +2633,8 @@
             int channelCount,
             int frameCount,
             uint32_t flags,
-            const sp<IMemory>& sharedBuffer)
+            const sp<IMemory>& sharedBuffer,
+            int sessionId)
     :   RefBase(),
         mThread(thread),
         mClient(client),
@@ -2277,7 +2643,8 @@
         mState(IDLE),
         mClientTid(-1),
         mFormat(format),
-        mFlags(flags & ~SYSTEM_FLAGS_MASK)
+        mFlags(flags & ~SYSTEM_FLAGS_MASK),
+        mSessionId(sessionId)
 {
     LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
 
@@ -2420,15 +2787,17 @@
             int format,
             int channelCount,
             int frameCount,
-            const sp<IMemory>& sharedBuffer)
-    :   TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer),
-    mMute(false), mSharedBuffer(sharedBuffer), mName(-1)
+            const sp<IMemory>& sharedBuffer,
+            int sessionId)
+    :   TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer, sessionId),
+    mMute(false), mSharedBuffer(sharedBuffer), mName(-1), mMainBuffer(NULL), mAuxBuffer(NULL), mAuxEffectId(0)
 {
     if (mCblk != NULL) {
         sp<ThreadBase> baseThread = thread.promote();
         if (baseThread != 0) {
             PlaybackThread *playbackThread = (PlaybackThread *)baseThread.get();
             mName = playbackThread->getTrackName_l();
+            mMainBuffer = playbackThread->mixBuffer();
         }
         LOGV("Track constructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
         if (mName < 0) {
@@ -2482,12 +2851,13 @@
 
 void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size)
 {
-    snprintf(buffer, size, "  %5d %5d %3u %3u %3u %04u %1d %1d %1d %5u %5u %5u  %08x %08x\n",
+    snprintf(buffer, size, "   %05d %05d %03u %03u %03u %05u   %04u %1d %1d %1d %05u %05u %05u  0x%08x 0x%08x 0x%08x 0x%08x\n",
             mName - AudioMixer::TRACK0,
             (mClient == NULL) ? getpid() : mClient->pid(),
             mStreamType,
             mFormat,
             mCblk->channelCount,
+            mSessionId,
             mFrameCount,
             mState,
             mMute,
@@ -2496,7 +2866,9 @@
             mCblk->volume[0],
             mCblk->volume[1],
             mCblk->server,
-            mCblk->user);
+            mCblk->user,
+            (int)mMainBuffer,
+            (int)mAuxBuffer);
 }
 
 status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
@@ -2679,6 +3051,23 @@
     mVolume[1] = right;
 }
 
+status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId)
+{
+    status_t status = DEAD_OBJECT;
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread != 0) {
+       PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+       status = playbackThread->attachAuxEffect(this, EffectId);
+    }
+    return status;
+}
+
+void AudioFlinger::PlaybackThread::Track::setAuxBuffer(int EffectId, int32_t *buffer)
+{
+    mAuxEffectId = EffectId;
+    mAuxBuffer = buffer;
+}
+
 // ----------------------------------------------------------------------------
 
 // RecordTrack constructor must be called with AudioFlinger::mLock held
@@ -2689,9 +3078,10 @@
             int format,
             int channelCount,
             int frameCount,
-            uint32_t flags)
+            uint32_t flags,
+            int sessionId)
     :   TrackBase(thread, client, sampleRate, format,
-                  channelCount, frameCount, flags, 0),
+                  channelCount, frameCount, flags, 0, sessionId),
         mOverflow(false)
 {
     if (mCblk != NULL) {
@@ -2779,10 +3169,11 @@
 
 void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size)
 {
-    snprintf(buffer, size, "   %05d %03u %03u %04u %01d %05u  %08x %08x\n",
+    snprintf(buffer, size, "   %05d %03u %03u %05d   %04u %01d %05u  %08x %08x\n",
             (mClient == NULL) ? getpid() : mClient->pid(),
             mFormat,
             mCblk->channelCount,
+            mSessionId,
             mFrameCount,
             mState,
             mCblk->sampleRate,
@@ -2800,7 +3191,7 @@
             int format,
             int channelCount,
             int frameCount)
-    :   Track(thread, NULL, AudioSystem::NUM_STREAM_TYPES, sampleRate, format, channelCount, frameCount, NULL),
+    :   Track(thread, NULL, AudioSystem::NUM_STREAM_TYPES, sampleRate, format, channelCount, frameCount, NULL, 0),
     mActive(false), mSourceThread(sourceThread)
 {
 
@@ -3115,6 +3506,11 @@
     return mTrack->getCblk();
 }
 
+status_t AudioFlinger::TrackHandle::attachAuxEffect(int EffectId)
+{
+    return mTrack->attachAuxEffect(EffectId);
+}
+
 status_t AudioFlinger::TrackHandle::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -3131,6 +3527,7 @@
         int channelCount,
         int frameCount,
         uint32_t flags,
+        int *sessionId,
         status_t *status)
 {
     sp<RecordThread::RecordTrack> recordTrack;
@@ -3140,6 +3537,7 @@
     status_t lStatus;
     RecordThread *thread;
     size_t inFrameCount;
+    int lSessionId;
 
     // check calling permissions
     if (!recordingAllowed()) {
@@ -3164,9 +3562,18 @@
             mClients.add(pid, client);
         }
 
+        // If no audio session id is provided, create one here
+        if (sessionId != NULL && *sessionId != 0) {
+            lSessionId = *sessionId;
+        } else {
+            lSessionId = nextUniqueId();
+            if (sessionId != NULL) {
+                *sessionId = lSessionId;
+            }
+        }
         // create new record track. The record track uses one track in mHardwareMixerThread by convention.
         recordTrack = new RecordThread::RecordTrack(thread, client, sampleRate,
-                                                   format, channelCount, frameCount, flags);
+                                                   format, channelCount, frameCount, flags, lSessionId);
     }
     if (recordTrack->getCblk() == NULL) {
         // remove local strong reference to Client before deleting the RecordTrack so that the Client
@@ -3504,7 +3911,7 @@
 
     if (mActiveTrack != 0) {
         result.append("Active Track:\n");
-        result.append("   Clien Fmt Chn Buf  S SRate  Serv     User\n");
+        result.append("   Clien Fmt Chn Session Buf  S SRate  Serv     User\n");
         mActiveTrack->dump(buffer, SIZE);
         result.append(buffer);
 
@@ -3753,14 +4160,15 @@
 
     mHardwareStatus = AUDIO_HW_IDLE;
     if (output != 0) {
+        int id = nextUniqueId();
         if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
             (format != AudioSystem::PCM_16_BIT) ||
             (channels != AudioSystem::CHANNEL_OUT_STEREO)) {
-            thread = new DirectOutputThread(this, output, ++mNextThreadId);
-            LOGV("openOutput() created direct output: ID %d thread %p", mNextThreadId, thread);
+            thread = new DirectOutputThread(this, output, id, *pDevices);
+            LOGV("openOutput() created direct output: ID %d thread %p", id, thread);
         } else {
-            thread = new MixerThread(this, output, ++mNextThreadId);
-            LOGV("openOutput() created mixer output: ID %d thread %p", mNextThreadId, thread);
+            thread = new MixerThread(this, output, id, *pDevices);
+            LOGV("openOutput() created mixer output: ID %d thread %p", id, thread);
 
 #ifdef LVMX
             unsigned bitsPerSample =
@@ -3774,7 +4182,7 @@
 #endif
 
         }
-        mPlaybackThreads.add(mNextThreadId, thread);
+        mPlaybackThreads.add(id, thread);
 
         if (pSamplingRate) *pSamplingRate = samplingRate;
         if (pFormat) *pFormat = format;
@@ -3783,7 +4191,7 @@
 
         // notify client processes of the new output creation
         thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
-        return mNextThreadId;
+        return id;
     }
 
     return 0;
@@ -3800,13 +4208,13 @@
         return 0;
     }
 
-
-    DuplicatingThread *thread = new DuplicatingThread(this, thread1, ++mNextThreadId);
+    int id = nextUniqueId();
+    DuplicatingThread *thread = new DuplicatingThread(this, thread1, id);
     thread->addOutputTrack(thread2);
-    mPlaybackThreads.add(mNextThreadId, thread);
+    mPlaybackThreads.add(id, thread);
     // notify client processes of the new output creation
     thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
-    return mNextThreadId;
+    return id;
 }
 
 status_t AudioFlinger::closeOutput(int output)
@@ -3925,10 +4333,11 @@
     }
 
     if (input != 0) {
+        int id = nextUniqueId();
          // Start record thread
-        thread = new RecordThread(this, input, reqSamplingRate, reqChannels, ++mNextThreadId);
-        mRecordThreads.add(mNextThreadId, thread);
-        LOGV("openInput() created record thread: ID %d thread %p", mNextThreadId, thread);
+        thread = new RecordThread(this, input, reqSamplingRate, reqChannels, id);
+        mRecordThreads.add(id, thread);
+        LOGV("openInput() created record thread: ID %d thread %p", id, thread);
         if (pSamplingRate) *pSamplingRate = reqSamplingRate;
         if (pFormat) *pFormat = format;
         if (pChannels) *pChannels = reqChannels;
@@ -3937,7 +4346,7 @@
 
         // notify client processes of the new input creation
         thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED);
-        return mNextThreadId;
+        return id;
     }
 
     return 0;
@@ -3991,6 +4400,12 @@
     return NO_ERROR;
 }
 
+
+int AudioFlinger::newAudioSessionId()
+{
+    return nextUniqueId();
+}
+
 // checkPlaybackThread_l() must be called with AudioFlinger::mLock held
 AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const
 {
@@ -4023,6 +4438,1475 @@
     return thread;
 }
 
+int AudioFlinger::nextUniqueId()
+{
+    return android_atomic_inc(&mNextUniqueId);
+}
+
+// ----------------------------------------------------------------------------
+//  Effect management
+// ----------------------------------------------------------------------------
+
+
+status_t AudioFlinger::loadEffectLibrary(const char *libPath, int *handle)
+{
+    Mutex::Autolock _l(mLock);
+    return EffectLoadLibrary(libPath, handle);
+}
+
+status_t AudioFlinger::unloadEffectLibrary(int handle)
+{
+    Mutex::Autolock _l(mLock);
+    return EffectUnloadLibrary(handle);
+}
+
+status_t AudioFlinger::queryNumberEffects(uint32_t *numEffects)
+{
+    Mutex::Autolock _l(mLock);
+    return EffectQueryNumberEffects(numEffects);
+}
+
+status_t AudioFlinger::queryNextEffect(effect_descriptor_t *descriptor)
+{
+    Mutex::Autolock _l(mLock);
+    return EffectQueryNext(descriptor);
+}
+
+status_t AudioFlinger::getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor)
+{
+    Mutex::Autolock _l(mLock);
+    return EffectGetDescriptor(pUuid, descriptor);
+}
+
+sp<IEffect> AudioFlinger::createEffect(pid_t pid,
+        effect_descriptor_t *pDesc,
+        const sp<IEffectClient>& effectClient,
+        int32_t priority,
+        int output,
+        int sessionId,
+        status_t *status,
+        int *id,
+        int *enabled)
+{
+    status_t lStatus = NO_ERROR;
+    sp<EffectHandle> handle;
+    effect_interface_t itfe;
+    effect_descriptor_t desc;
+    sp<Client> client;
+    wp<Client> wclient;
+
+    LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, output %d", pid, effectClient.get(), priority, sessionId, output);
+
+    if (pDesc == NULL) {
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    {
+        Mutex::Autolock _l(mLock);
+
+        if (!EffectIsNullUuid(&pDesc->uuid)) {
+            // if uuid is specified, request effect descriptor
+            lStatus = EffectGetDescriptor(&pDesc->uuid, &desc);
+            if (lStatus < 0) {
+                LOGW("createEffect() error %d from EffectGetDescriptor", lStatus);
+                goto Exit;
+            }
+        } else {
+            // if uuid is not specified, look for an available implementation
+            // of the required type in effect factory
+            if (EffectIsNullUuid(&pDesc->type)) {
+                LOGW("createEffect() no effect type");
+                lStatus = BAD_VALUE;
+                goto Exit;
+            }
+            uint32_t numEffects = 0;
+            effect_descriptor_t d;
+            bool found = false;
+
+            lStatus = EffectQueryNumberEffects(&numEffects);
+            if (lStatus < 0) {
+                LOGW("createEffect() error %d from EffectQueryNumberEffects", lStatus);
+                goto Exit;
+            }
+            for (; numEffects > 0; numEffects--) {
+                lStatus = EffectQueryNext(&desc);
+                if (lStatus < 0) {
+                    LOGW("createEffect() error %d from EffectQueryNext", lStatus);
+                    continue;
+                }
+                if (memcmp(&desc.type, &pDesc->type, sizeof(effect_uuid_t)) == 0) {
+                    // If matching type found save effect descriptor. If the session is
+                    // 0 and the effect is not auxiliary, continue enumeration in case
+                    // an auxiliary version of this effect type is available
+                    found = true;
+                    memcpy(&d, &desc, sizeof(effect_descriptor_t));
+                    if (sessionId != 0 ||
+                            (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+                        break;
+                    }
+                }
+            }
+            if (!found) {
+                lStatus = BAD_VALUE;
+                LOGW("createEffect() effect not found");
+                goto Exit;
+            }
+            // For same effect type, chose auxiliary version over insert version if
+            // connect to output mix (Compliance to OpenSL ES)
+            if (sessionId == 0 &&
+                    (d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) {
+                memcpy(&desc, &d, sizeof(effect_descriptor_t));
+            }
+        }
+
+        // Do not allow auxiliary effects on a session different from 0 (output mix)
+        if (sessionId != 0 &&
+             (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+            lStatus = INVALID_OPERATION;
+            goto Exit;
+        }
+
+        // return effect descriptor
+        memcpy(pDesc, &desc, sizeof(effect_descriptor_t));
+
+        // If output is not specified try to find a matching audio session ID in one of the
+        // output threads.
+        // TODO: allow attachment of effect to inputs
+        if (output == 0) {
+            if (sessionId == 0) {
+                // default to first output
+                // TODO: define criteria to choose output when not specified. Or
+                // receive output from audio policy manager
+                if (mPlaybackThreads.size() != 0) {
+                    output = mPlaybackThreads.keyAt(0);
+                }
+            } else {
+                 // look for the thread where the specified audio session is present
+                for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+                    if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId)) {
+                        output = mPlaybackThreads.keyAt(i);
+                        break;
+                    }
+                }
+            }
+        }
+        PlaybackThread *thread = checkPlaybackThread_l(output);
+        if (thread == NULL) {
+            LOGE("unknown output thread");
+            lStatus = BAD_VALUE;
+            goto Exit;
+        }
+
+        wclient = mClients.valueFor(pid);
+
+        if (wclient != NULL) {
+            client = wclient.promote();
+        } else {
+            client = new Client(this, pid);
+            mClients.add(pid, client);
+        }
+
+        // create effect on selected output trhead
+        handle = thread->createEffect_l(client, effectClient, priority, sessionId, &desc, enabled, &lStatus);
+        if (handle != 0 && id != NULL) {
+            *id = handle->id();
+        }
+    }
+
+Exit:
+    if(status) {
+        *status = lStatus;
+    }
+    return handle;
+}
+
+// PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held
+sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
+        const sp<AudioFlinger::Client>& client,
+        const sp<IEffectClient>& effectClient,
+        int32_t priority,
+        int sessionId,
+        effect_descriptor_t *desc,
+        int *enabled,
+        status_t *status
+        )
+{
+    sp<EffectModule> effect;
+    sp<EffectHandle> handle;
+    status_t lStatus;
+    sp<Track> track;
+    sp<EffectChain> chain;
+    bool effectCreated = false;
+
+    if (mOutput == 0) {
+        LOGW("createEffect_l() Audio driver not initialized.");
+        lStatus = NO_INIT;
+        goto Exit;
+    }
+
+    // Do not allow auxiliary effect on session other than 0
+    if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY &&
+        sessionId != 0) {
+        LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    // Do not allow effects with session ID 0 on direct output or duplicating threads
+    // TODO: add rule for hw accelerated effects on direct outputs with non PCM format
+    if (sessionId == 0 && mType != MIXER) {
+        LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    LOGV("createEffect_l() thread %p effect %s on session %d", this, desc->name, sessionId);
+
+    { // scope for mLock
+        Mutex::Autolock _l(mLock);
+
+        // check for existing effect chain with the requested audio session
+        chain = getEffectChain_l(sessionId);
+        if (chain == 0) {
+            // create a new chain for this session
+            LOGV("createEffect_l() new effect chain for session %d", sessionId);
+            chain = new EffectChain(this, sessionId);
+            addEffectChain_l(chain);
+        } else {
+            effect = chain->getEffectFromDesc(desc);
+        }
+
+        LOGV("createEffect_l() got effect %p on chain %p", effect == 0 ? 0 : effect.get(), chain.get());
+
+        if (effect == 0) {
+            // create a new effect module if none present in the chain
+            effectCreated = true;
+            effect = new EffectModule(this, chain, desc, mAudioFlinger->nextUniqueId(), sessionId);
+            lStatus = effect->status();
+            if (lStatus != NO_ERROR) {
+                goto Exit;
+            }
+            //TODO: handle CPU load and memory usage here
+            lStatus = chain->addEffect(effect);
+            if (lStatus != NO_ERROR) {
+                goto Exit;
+            }
+
+            effect->setDevice(mDevice);
+        }
+        // create effect handle and connect it to effect module
+        handle = new EffectHandle(effect, client, effectClient, priority);
+        lStatus = effect->addHandle(handle);
+        if (enabled) {
+            *enabled = (int)effect->isEnabled();
+        }
+    }
+
+Exit:
+    if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
+        if (chain != 0 && effectCreated) {
+            if (chain->removeEffect(effect) == 0) {
+                removeEffectChain_l(chain);
+            }
+        }
+        handle.clear();
+    }
+
+    if(status) {
+        *status = lStatus;
+    }
+    return handle;
+}
+
+status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain)
+{
+    int session = chain->sessionId();
+    int16_t *buffer = mMixBuffer;
+
+    LOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
+    if (session == 0) {
+        chain->setInBuffer(buffer, false);
+        chain->setOutBuffer(buffer);
+        // Effect chain for session 0 is inserted at end of effect chains list
+        // to be processed last as it contains output mix effects to apply after
+        // all track specific effects
+        mEffectChains.add(chain);
+    } else {
+        bool ownsBuffer = false;
+        // Only one effect chain can be present in direct output thread and it uses
+        // the mix buffer as input
+        if (mType != DIRECT) {
+            size_t numSamples = mFrameCount * mChannelCount;
+            buffer = new int16_t[numSamples];
+            memset(buffer, 0, numSamples * sizeof(int16_t));
+            LOGV("addEffectChain_l() creating new input buffer %p session %d", buffer, session);
+            ownsBuffer = true;
+        }
+        chain->setInBuffer(buffer, ownsBuffer);
+        chain->setOutBuffer(mMixBuffer);
+        // Effect chain for session other than 0 is inserted at beginning of effect
+        // chains list to be processed before output mix effects. Relative order between
+        // sessions other than 0 is not important
+        mEffectChains.insertAt(chain, 0);
+    }
+
+    // Attach all tracks with same session ID to this chain.
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        sp<Track> track = mTracks[i];
+        if (session == track->sessionId()) {
+            LOGV("addEffectChain_l() track->setMainBuffer track %p buffer %p", track.get(), buffer);
+            track->setMainBuffer(buffer);
+        }
+    }
+
+    // indicate all active tracks in the chain
+    for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) {
+        sp<Track> track = mActiveTracks[i].promote();
+        if (track == 0) continue;
+        if (session == track->sessionId()) {
+            LOGV("addEffectChain_l() activating track %p on session %d", track.get(), session);
+            chain->startTrack();
+        }
+    }
+
+    return NO_ERROR;
+}
+
+size_t AudioFlinger::PlaybackThread::removeEffectChain_l(const sp<EffectChain>& chain)
+{
+    int session = chain->sessionId();
+
+    LOGV("removeEffectChain_l() %p from thread %p for session %d", chain.get(), this, session);
+
+    for (size_t i = 0; i < mEffectChains.size(); i++) {
+        if (chain == mEffectChains[i]) {
+            mEffectChains.removeAt(i);
+            // detach all tracks with same session ID from this chain
+            for (size_t i = 0; i < mTracks.size(); ++i) {
+                sp<Track> track = mTracks[i];
+                if (session == track->sessionId()) {
+                    track->setMainBuffer(mMixBuffer);
+                }
+            }
+        }
+    }
+    return mEffectChains.size();
+}
+
+void AudioFlinger::PlaybackThread::lockEffectChains_l()
+{
+    for (size_t i = 0; i < mEffectChains.size(); i++) {
+        mEffectChains[i]->lock();
+    }
+}
+
+void AudioFlinger::PlaybackThread::unlockEffectChains()
+{
+    Mutex::Autolock _l(mLock);
+    for (size_t i = 0; i < mEffectChains.size(); i++) {
+        mEffectChains[i]->unlock();
+    }
+}
+
+sp<AudioFlinger::EffectModule> AudioFlinger::PlaybackThread::getEffect_l(int sessionId, int effectId)
+{
+    sp<EffectModule> effect;
+
+    sp<EffectChain> chain = getEffectChain_l(sessionId);
+    if (chain != 0) {
+        effect = chain->getEffectFromId(effectId);
+    }
+    return effect;
+}
+
+status_t AudioFlinger::PlaybackThread::attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
+{
+    Mutex::Autolock _l(mLock);
+    return attachAuxEffect_l(track, EffectId);
+}
+
+status_t AudioFlinger::PlaybackThread::attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
+{
+    status_t status = NO_ERROR;
+
+    if (EffectId == 0) {
+        track->setAuxBuffer(0, NULL);
+    } else {
+        // Auxiliary effects are always in audio session 0
+        sp<EffectModule> effect = getEffect_l(0, EffectId);
+        if (effect != 0) {
+            if ((effect->desc().flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+                track->setAuxBuffer(EffectId, (int32_t *)effect->inBuffer());
+            } else {
+                status = INVALID_OPERATION;
+            }
+        } else {
+            status = BAD_VALUE;
+        }
+    }
+    return status;
+}
+
+void AudioFlinger::PlaybackThread::detachAuxEffect_l(int effectId)
+{
+     for (size_t i = 0; i < mTracks.size(); ++i) {
+        sp<Track> track = mTracks[i];
+        if (track->auxEffectId() == effectId) {
+            attachAuxEffect_l(track, 0);
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+//  EffectModule implementation
+// ----------------------------------------------------------------------------
+
+#undef LOG_TAG
+#define LOG_TAG "AudioFlinger::EffectModule"
+
+AudioFlinger::EffectModule::EffectModule(const wp<ThreadBase>& wThread,
+                                        const wp<AudioFlinger::EffectChain>& chain,
+                                        effect_descriptor_t *desc,
+                                        int id,
+                                        int sessionId)
+    : mThread(wThread), mChain(chain), mId(id), mSessionId(sessionId), mEffectInterface(NULL),
+      mStatus(NO_INIT), mState(IDLE)
+{
+    LOGV("Constructor %p", this);
+    int lStatus;
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread == 0) {
+        return;
+    }
+    PlaybackThread *p = (PlaybackThread *)thread.get();
+
+    memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t));
+
+    // create effect engine from effect factory
+    mStatus = EffectCreate(&desc->uuid, &mEffectInterface);
+    if (mStatus != NO_ERROR) {
+        return;
+    }
+    lStatus = init();
+    if (lStatus < 0) {
+        mStatus = lStatus;
+        goto Error;
+    }
+
+    LOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface);
+    return;
+Error:
+    EffectRelease(mEffectInterface);
+    mEffectInterface = NULL;
+    LOGV("Constructor Error %d", mStatus);
+}
+
+AudioFlinger::EffectModule::~EffectModule()
+{
+    LOGV("Destructor %p", this);
+    if (mEffectInterface != NULL) {
+        // release effect engine
+        EffectRelease(mEffectInterface);
+    }
+}
+
+status_t AudioFlinger::EffectModule::addHandle(sp<EffectHandle>& handle)
+{
+    status_t status;
+
+    Mutex::Autolock _l(mLock);
+    // First handle in mHandles has highest priority and controls the effect module
+    int priority = handle->priority();
+    size_t size = mHandles.size();
+    sp<EffectHandle> h;
+    size_t i;
+    for (i = 0; i < size; i++) {
+        h = mHandles[i].promote();
+        if (h == 0) continue;
+        if (h->priority() <= priority) break;
+    }
+    // if inserted in first place, move effect control from previous owner to this handle
+    if (i == 0) {
+        if (h != 0) {
+            h->setControl(false, true);
+        }
+        handle->setControl(true, false);
+        status = NO_ERROR;
+    } else {
+        status = ALREADY_EXISTS;
+    }
+    mHandles.insertAt(handle, i);
+    return status;
+}
+
+size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle)
+{
+    Mutex::Autolock _l(mLock);
+    size_t size = mHandles.size();
+    size_t i;
+    for (i = 0; i < size; i++) {
+        if (mHandles[i] == handle) break;
+    }
+    if (i == size) {
+        return size;
+    }
+    mHandles.removeAt(i);
+    size = mHandles.size();
+    // if removed from first place, move effect control from this handle to next in line
+    if (i == 0 && size != 0) {
+        sp<EffectHandle> h = mHandles[0].promote();
+        if (h != 0) {
+            h->setControl(true, true);
+        }
+    }
+
+    return size;
+}
+
+void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle)
+{
+    // keep a strong reference on this EffectModule to avoid calling the
+    // destructor before we exit
+    sp<EffectModule> keep(this);
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread != 0) {
+        Mutex::Autolock _l(thread->mLock);
+        // delete the effect module if removing last handle on it
+        if (removeHandle(handle) == 0) {
+            PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+            if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+                playbackThread->detachAuxEffect_l(mId);
+            }
+            sp<EffectChain> chain = mChain.promote();
+            if (chain != 0) {
+                // remove effect chain if remove last effect
+                if (chain->removeEffect(keep) == 0) {
+                    playbackThread->removeEffectChain_l(chain);
+                }
+            }
+        }
+    }
+}
+
+void AudioFlinger::EffectModule::process()
+{
+    Mutex::Autolock _l(mLock);
+
+    if (mEffectInterface == NULL || mConfig.inputCfg.buffer.raw == NULL || mConfig.outputCfg.buffer.raw == NULL) {
+        return;
+    }
+
+    if (mState != IDLE) {
+        // do 32 bit to 16 bit conversion for auxiliary effect input buffer
+        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+            AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32,
+                                        mConfig.inputCfg.buffer.s32,
+                                        mConfig.inputCfg.buffer.frameCount);
+        }
+
+        // TODO: handle effects with buffer provider
+        if (mState != ACTIVE) {
+            uint32_t count = mConfig.inputCfg.buffer.frameCount;
+            int32_t amp = 32767L << 16;
+            int32_t step = amp / count;
+            int16_t *pIn = mConfig.inputCfg.buffer.s16;
+            int16_t *pOut = mConfig.outputCfg.buffer.s16;
+            int inChannels;
+            int outChannels;
+
+            if (mConfig.inputCfg.channels == CHANNEL_MONO) {
+                inChannels = 1;
+            } else {
+                inChannels = 2;
+            }
+            if (mConfig.outputCfg.channels == CHANNEL_MONO) {
+                outChannels = 1;
+            } else {
+                outChannels = 2;
+            }
+
+            switch (mState) {
+            case RESET:
+                reset();
+                // clear auxiliary effect input buffer for next accumulation
+                if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+                    memset(mConfig.inputCfg.buffer.raw, 0, mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
+                }
+                step = -step;
+                mState = STARTING;
+                break;
+            case STARTING:
+                start();
+                amp = 0;
+                pOut = mConfig.inputCfg.buffer.s16;
+                outChannels = inChannels;
+                mState = ACTIVE;
+                break;
+            case STOPPING:
+                step = -step;
+                pOut = mConfig.inputCfg.buffer.s16;
+                outChannels = inChannels;
+                mState = STOPPED;
+                break;
+            case STOPPED:
+                stop();
+                amp = 0;
+                mState = IDLE;
+                break;
+            }
+
+            // ramp volume down or up before activating or deactivating the effect
+            if (inChannels == 1) {
+                if (outChannels == 1) {
+                    while (count--) {
+                        *pOut++ = (int16_t)(((int32_t)*pIn++ * (amp >> 16)) >> 15);
+                        amp += step;
+                    }
+                } else {
+                    while (count--) {
+                        int32_t smp = (int16_t)(((int32_t)*pIn++ * (amp >> 16)) >> 15);
+                        *pOut++ = smp;
+                        *pOut++ = smp;
+                        amp += step;
+                    }
+                }
+            } else {
+                if (outChannels == 1) {
+                    while (count--) {
+                        int32_t smp = (((int32_t)*pIn * (amp >> 16)) >> 16) +
+                                      (((int32_t)*(pIn + 1) * (amp >> 16)) >> 16);
+                        pIn += 2;
+                        *pOut++ = (int16_t)smp;
+                        amp += step;
+                    }
+                } else {
+                    while (count--) {
+                        *pOut++ = (int16_t)((int32_t)*pIn++ * (amp >> 16)) >> 15;
+                        *pOut++ = (int16_t)((int32_t)*pIn++ * (amp >> 16)) >> 15;
+                         amp += step;
+                    }
+                }
+            }
+            if (mState == STARTING || mState == IDLE) {
+                return;
+            }
+        }
+
+        // do the actual processing in the effect engine
+        (*mEffectInterface)->process(mEffectInterface, &mConfig.inputCfg.buffer, &mConfig.outputCfg.buffer);
+
+        // clear auxiliary effect input buffer for next accumulation
+        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+            memset(mConfig.inputCfg.buffer.raw, 0, mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
+        }
+    } else if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT &&
+                mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw){
+        // If an insert effect is idle and input buffer is different from output buffer, copy input to
+        // output
+        sp<EffectChain> chain = mChain.promote();
+        if (chain != 0 && chain->activeTracks() != 0) {
+            size_t size = mConfig.inputCfg.buffer.frameCount * sizeof(int16_t);
+            if (mConfig.inputCfg.channels == CHANNEL_STEREO) {
+                size *= 2;
+            }
+            memcpy(mConfig.outputCfg.buffer.raw, mConfig.inputCfg.buffer.raw, size);
+        }
+    }
+}
+
+void AudioFlinger::EffectModule::reset()
+{
+    if (mEffectInterface == NULL) {
+        return;
+    }
+    (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_RESET, 0, NULL, 0, NULL);
+}
+
+status_t AudioFlinger::EffectModule::configure()
+{
+    uint32_t channels;
+    if (mEffectInterface == NULL) {
+        return NO_INIT;
+    }
+
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread == 0) {
+        return DEAD_OBJECT;
+    }
+
+    // TODO: handle configuration of effects replacing track process
+    if (thread->channelCount() == 1) {
+        channels = CHANNEL_MONO;
+    } else {
+        channels = CHANNEL_STEREO;
+    }
+
+    if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+        mConfig.inputCfg.channels = CHANNEL_MONO;
+    } else {
+        mConfig.inputCfg.channels = channels;
+    }
+    mConfig.outputCfg.channels = channels;
+    mConfig.inputCfg.format = PCM_FORMAT_S15;
+    mConfig.outputCfg.format = PCM_FORMAT_S15;
+    mConfig.inputCfg.samplingRate = thread->sampleRate();
+    mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate;
+    mConfig.inputCfg.bufferProvider.cookie = NULL;
+    mConfig.inputCfg.bufferProvider.getBuffer = NULL;
+    mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
+    mConfig.outputCfg.bufferProvider.cookie = NULL;
+    mConfig.outputCfg.bufferProvider.getBuffer = NULL;
+    mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
+    mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+    // Insert effect:
+    // - in session 0, always overwrites output buffer: input buffer == output buffer
+    // - in other sessions:
+    //      last effect in the chain accumulates in output buffer: input buffer != output buffer
+    //      other effect: overwrites output buffer: input buffer == output buffer
+    // Auxiliary effect:
+    //      accumulates in output buffer: input buffer != output buffer
+    // Therefore: accumulate <=> input buffer != output buffer
+    if (mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) {
+        mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+    } else {
+        mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
+    }
+    mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
+    mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
+    mConfig.inputCfg.buffer.frameCount = thread->frameCount();
+    mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount;
+
+    status_t cmdStatus;
+    int size = sizeof(int);
+    status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_CONFIGURE, sizeof(effect_config_t), &mConfig, &size, &cmdStatus);
+    if (status == 0) {
+        status = cmdStatus;
+    }
+    return status;
+}
+
+status_t AudioFlinger::EffectModule::init()
+{
+    if (mEffectInterface == NULL) {
+        return NO_INIT;
+    }
+    status_t cmdStatus;
+    int size = sizeof(status_t);
+    status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_INIT, 0, NULL, &size, &cmdStatus);
+    if (status == 0) {
+        status = cmdStatus;
+    }
+    return status;
+}
+
+status_t AudioFlinger::EffectModule::start()
+{
+    if (mEffectInterface == NULL) {
+        return NO_INIT;
+    }
+    status_t cmdStatus;
+    int size = sizeof(status_t);
+    status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_ENABLE, 0, NULL, &size, &cmdStatus);
+    if (status == 0) {
+        status = cmdStatus;
+    }
+    return status;
+}
+
+status_t AudioFlinger::EffectModule::stop()
+{
+    if (mEffectInterface == NULL) {
+        return NO_INIT;
+    }
+    status_t cmdStatus;
+    int size = sizeof(status_t);
+    status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_DISABLE, 0, NULL, &size, &cmdStatus);
+    if (status == 0) {
+        status = cmdStatus;
+    }
+    return status;
+}
+
+status_t AudioFlinger::EffectModule::command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData)
+{
+    LOGV("command(), cmdCode: %d, mEffectInterface: %p", cmdCode, mEffectInterface);
+
+    if (mEffectInterface == NULL) {
+        return NO_INIT;
+    }
+    status_t status = (*mEffectInterface)->command(mEffectInterface, cmdCode, cmdSize, pCmdData, replySize, pReplyData);
+    if (cmdCode != EFFECT_CMD_GET_PARAM && status == NO_ERROR) {
+        int size = (replySize == NULL) ? 0 : *replySize;
+        Mutex::Autolock _l(mLock);
+        for (size_t i = 1; i < mHandles.size(); i++) {
+            sp<EffectHandle> h = mHandles[i].promote();
+            if (h != 0) {
+                h->commandExecuted(cmdCode, cmdSize, pCmdData, size, pReplyData);
+            }
+        }
+    }
+    return status;
+}
+
+status_t AudioFlinger::EffectModule::setEnabled(bool enabled)
+{
+    Mutex::Autolock _l(mLock);
+    LOGV("setEnabled %p enabled %d", this, enabled);
+
+    if (enabled != isEnabled()) {
+        switch (mState) {
+        // going from disabled to enabled
+        case IDLE:
+            mState = RESET;
+            break;
+        case STOPPING:
+            mState = ACTIVE;
+            break;
+        case STOPPED:
+            mState = STARTING;
+            break;
+
+        // going from enabled to disabled
+        case RESET:
+            mState = IDLE;
+            break;
+        case STARTING:
+            mState = STOPPED;
+            break;
+        case ACTIVE:
+            mState = STOPPING;
+            break;
+        }
+        for (size_t i = 1; i < mHandles.size(); i++) {
+            sp<EffectHandle> h = mHandles[i].promote();
+            if (h != 0) {
+                h->setEnabled(enabled);
+            }
+        }
+    }
+    return NO_ERROR;
+}
+
+bool AudioFlinger::EffectModule::isEnabled()
+{
+    switch (mState) {
+    case RESET:
+    case STARTING:
+    case ACTIVE:
+        return true;
+    case IDLE:
+    case STOPPING:
+    case STOPPED:
+    default:
+        return false;
+    }
+}
+
+status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller)
+{
+    status_t status = NO_ERROR;
+
+    // Send volume indication if EFFECT_FLAG_VOLUME_IND is set and read back altered volume
+    // if controller flag is set (Note that controller == TRUE => EFFECT_FLAG_VOLUME_CTRL set)
+    if ((mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) & (EFFECT_FLAG_VOLUME_CTRL|EFFECT_FLAG_VOLUME_IND)) {
+        status_t cmdStatus;
+        uint32_t volume[2];
+        uint32_t *pVolume = NULL;
+        int size = sizeof(volume);
+        volume[0] = *left;
+        volume[1] = *right;
+        if (controller) {
+            pVolume = volume;
+        }
+        status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_VOLUME, size, volume, &size, pVolume);
+        if (controller && status == NO_ERROR && size == sizeof(volume)) {
+            *left = volume[0];
+            *right = volume[1];
+        }
+    }
+    return status;
+}
+
+status_t AudioFlinger::EffectModule::setDevice(uint32_t device)
+{
+    status_t status = NO_ERROR;
+    if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_MASK) {
+        status_t cmdStatus;
+        int size = sizeof(status_t);
+        status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_DEVICE, sizeof(uint32_t), &device, &size, &cmdStatus);
+        if (status == NO_ERROR) {
+            status = cmdStatus;
+        }
+    }
+    return status;
+}
+
+
+status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "\tEffect ID %d:\n", mId);
+    result.append(buffer);
+
+    bool locked = tryLock(mLock);
+    // failed to lock - AudioFlinger is probably deadlocked
+    if (!locked) {
+        result.append("\t\tCould not lock Fx mutex:\n");
+    }
+
+    result.append("\t\tSession Status State Engine:\n");
+    snprintf(buffer, SIZE, "\t\t%05d   %03d    %03d   0x%08x\n",
+            mSessionId, mStatus, mState, (uint32_t)mEffectInterface);
+    result.append(buffer);
+
+    result.append("\t\tDescriptor:\n");
+    snprintf(buffer, SIZE, "\t\t- UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
+            mDescriptor.uuid.timeLow, mDescriptor.uuid.timeMid, mDescriptor.uuid.timeHiAndVersion,
+            mDescriptor.uuid.clockSeq, mDescriptor.uuid.node[0], mDescriptor.uuid.node[1],mDescriptor.uuid.node[2],
+            mDescriptor.uuid.node[3],mDescriptor.uuid.node[4],mDescriptor.uuid.node[5]);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\t\t- TYPE: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
+                mDescriptor.type.timeLow, mDescriptor.type.timeMid, mDescriptor.type.timeHiAndVersion,
+                mDescriptor.type.clockSeq, mDescriptor.type.node[0], mDescriptor.type.node[1],mDescriptor.type.node[2],
+                mDescriptor.type.node[3],mDescriptor.type.node[4],mDescriptor.type.node[5]);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\t\t- apiVersion: %04X\n\t\t- flags: %08X\n",
+            mDescriptor.apiVersion,
+            mDescriptor.flags);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\t\t- name: %s\n",
+            mDescriptor.name);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\t\t- implementor: %s\n",
+            mDescriptor.implementor);
+    result.append(buffer);
+
+    result.append("\t\t- Input configuration:\n");
+    result.append("\t\t\tBuffer     Frames  Smp rate Channels Format\n");
+    snprintf(buffer, SIZE, "\t\t\t0x%08x %05d   %05d    %08x %d\n",
+            (uint32_t)mConfig.inputCfg.buffer.raw,
+            mConfig.inputCfg.buffer.frameCount,
+            mConfig.inputCfg.samplingRate,
+            mConfig.inputCfg.channels,
+            mConfig.inputCfg.format);
+    result.append(buffer);
+
+    result.append("\t\t- Output configuration:\n");
+    result.append("\t\t\tBuffer     Frames  Smp rate Channels Format\n");
+    snprintf(buffer, SIZE, "\t\t\t0x%08x %05d   %05d    %08x %d\n",
+            (uint32_t)mConfig.outputCfg.buffer.raw,
+            mConfig.outputCfg.buffer.frameCount,
+            mConfig.outputCfg.samplingRate,
+            mConfig.outputCfg.channels,
+            mConfig.outputCfg.format);
+    result.append(buffer);
+
+    snprintf(buffer, SIZE, "\t\t%d Clients:\n", mHandles.size());
+    result.append(buffer);
+    result.append("\t\t\tPid   Priority Ctrl Locked client server\n");
+    for (size_t i = 0; i < mHandles.size(); ++i) {
+        sp<EffectHandle> handle = mHandles[i].promote();
+        if (handle != 0) {
+            handle->dump(buffer, SIZE);
+            result.append(buffer);
+        }
+    }
+
+    result.append("\n");
+
+    write(fd, result.string(), result.length());
+
+    if (locked) {
+        mLock.unlock();
+    }
+
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+//  EffectHandle implementation
+// ----------------------------------------------------------------------------
+
+#undef LOG_TAG
+#define LOG_TAG "AudioFlinger::EffectHandle"
+
+AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect,
+                                        const sp<AudioFlinger::Client>& client,
+                                        const sp<IEffectClient>& effectClient,
+                                        int32_t priority)
+    : BnEffect(),
+    mEffect(effect), mEffectClient(effectClient), mClient(client), mPriority(priority), mHasControl(false)
+{
+    LOGV("constructor %p", this);
+
+    int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int);
+    mCblkMemory = client->heap()->allocate(EFFECT_PARAM_BUFFER_SIZE + bufOffset);
+    if (mCblkMemory != 0) {
+        mCblk = static_cast<effect_param_cblk_t *>(mCblkMemory->pointer());
+
+        if (mCblk) {
+            new(mCblk) effect_param_cblk_t();
+            mBuffer = (uint8_t *)mCblk + bufOffset;
+         }
+    } else {
+        LOGE("not enough memory for Effect size=%u", EFFECT_PARAM_BUFFER_SIZE + sizeof(effect_param_cblk_t));
+        return;
+    }
+}
+
+AudioFlinger::EffectHandle::~EffectHandle()
+{
+    LOGV("Destructor %p", this);
+    disconnect();
+}
+
+status_t AudioFlinger::EffectHandle::enable()
+{
+    if (!mHasControl) return INVALID_OPERATION;
+    if (mEffect == 0) return DEAD_OBJECT;
+
+    return mEffect->setEnabled(true);
+}
+
+status_t AudioFlinger::EffectHandle::disable()
+{
+    if (!mHasControl) return INVALID_OPERATION;
+    if (mEffect == NULL) return DEAD_OBJECT;
+
+    return mEffect->setEnabled(false);
+}
+
+void AudioFlinger::EffectHandle::disconnect()
+{
+    if (mEffect == 0) {
+        return;
+    }
+    mEffect->disconnect(this);
+    // release sp on module => module destructor can be called now
+    mEffect.clear();
+    if (mCblk) {
+        mCblk->~effect_param_cblk_t();   // destroy our shared-structure.
+    }
+    mCblkMemory.clear();            // and free the shared memory
+    if (mClient != 0) {
+        Mutex::Autolock _l(mClient->audioFlinger()->mLock);
+        mClient.clear();
+    }
+}
+
+status_t AudioFlinger::EffectHandle::command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData)
+{
+    LOGV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p", cmdCode, mHasControl, (mEffect == 0) ? 0 : mEffect.get());
+
+    // only get parameter command is permitted for applications not controlling the effect
+    if (!mHasControl && cmdCode != EFFECT_CMD_GET_PARAM) {
+        return INVALID_OPERATION;
+    }
+    if (mEffect == 0) return DEAD_OBJECT;
+
+    // handle commands that are not forwarded transparently to effect engine
+    if (cmdCode == EFFECT_CMD_SET_PARAM_COMMIT) {
+        // No need to trylock() here as this function is executed in the binder thread serving a particular client process:
+        // no risk to block the whole media server process or mixer threads is we are stuck here
+        Mutex::Autolock _l(mCblk->lock);
+        if (mCblk->clientIndex > EFFECT_PARAM_BUFFER_SIZE ||
+            mCblk->serverIndex > EFFECT_PARAM_BUFFER_SIZE) {
+            mCblk->serverIndex = 0;
+            mCblk->clientIndex = 0;
+            return BAD_VALUE;
+        }
+        status_t status = NO_ERROR;
+        while (mCblk->serverIndex < mCblk->clientIndex) {
+            int reply;
+            int rsize = sizeof(int);
+            int *p = (int *)(mBuffer + mCblk->serverIndex);
+            int size = *p++;
+            effect_param_t *param = (effect_param_t *)p;
+            int psize = sizeof(effect_param_t) + ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize;
+            status_t ret = mEffect->command(EFFECT_CMD_SET_PARAM, psize, p, &rsize, &reply);
+            if (ret == NO_ERROR) {
+                if (reply != NO_ERROR) {
+                    status = reply;
+                }
+            } else {
+                status = ret;
+            }
+            mCblk->serverIndex += size;
+        }
+        mCblk->serverIndex = 0;
+        mCblk->clientIndex = 0;
+        return status;
+    } else if (cmdCode == EFFECT_CMD_ENABLE) {
+        return enable();
+    } else if (cmdCode == EFFECT_CMD_DISABLE) {
+        return disable();
+    }
+
+    return mEffect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
+}
+
+sp<IMemory> AudioFlinger::EffectHandle::getCblk() const {
+    return mCblkMemory;
+}
+
+void AudioFlinger::EffectHandle::setControl(bool hasControl, bool signal)
+{
+    LOGV("setControl %p control %d", this, hasControl);
+
+    mHasControl = hasControl;
+    if (signal && mEffectClient != 0) {
+        mEffectClient->controlStatusChanged(hasControl);
+    }
+}
+
+void AudioFlinger::EffectHandle::commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData)
+{
+    if (mEffectClient != 0) {
+        mEffectClient->commandExecuted(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
+    }
+}
+
+
+
+void AudioFlinger::EffectHandle::setEnabled(bool enabled)
+{
+    if (mEffectClient != 0) {
+        mEffectClient->enableStatusChanged(enabled);
+    }
+}
+
+status_t AudioFlinger::EffectHandle::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    return BnEffect::onTransact(code, data, reply, flags);
+}
+
+
+void AudioFlinger::EffectHandle::dump(char* buffer, size_t size)
+{
+    bool locked = tryLock(mCblk->lock);
+
+    snprintf(buffer, size, "\t\t\t%05d %05d    %01u    %01u      %05u  %05u\n",
+            (mClient == NULL) ? getpid() : mClient->pid(),
+            mPriority,
+            mHasControl,
+            !locked,
+            mCblk->clientIndex,
+            mCblk->serverIndex
+            );
+
+    if (locked) {
+        mCblk->lock.unlock();
+    }
+}
+
+#undef LOG_TAG
+#define LOG_TAG "AudioFlinger::EffectChain"
+
+AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& wThread,
+                                        int sessionId)
+    : mThread(wThread), mSessionId(sessionId), mVolumeCtrlIdx(-1), mActiveTrackCnt(0), mOwnInBuffer(false)
+{
+
+}
+
+AudioFlinger::EffectChain::~EffectChain()
+{
+    if (mOwnInBuffer) {
+        delete mInBuffer;
+    }
+
+}
+
+sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromDesc(effect_descriptor_t *descriptor)
+{
+    sp<EffectModule> effect;
+    size_t size = mEffects.size();
+
+    for (size_t i = 0; i < size; i++) {
+        if (memcmp(&mEffects[i]->desc().uuid, &descriptor->uuid, sizeof(effect_uuid_t)) == 0) {
+            effect = mEffects[i];
+            break;
+        }
+    }
+    return effect;
+}
+
+sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId(int id)
+{
+    sp<EffectModule> effect;
+    size_t size = mEffects.size();
+
+    for (size_t i = 0; i < size; i++) {
+        if (mEffects[i]->id() == id) {
+            effect = mEffects[i];
+            break;
+        }
+    }
+    return effect;
+}
+
+// Must be called with EffectChain::mLock locked
+void AudioFlinger::EffectChain::process_l()
+{
+    size_t size = mEffects.size();
+    for (size_t i = 0; i < size; i++) {
+        mEffects[i]->process();
+    }
+    // if no track is active, input buffer must be cleared here as the mixer process
+    // will not do it
+    if (mSessionId != 0 && activeTracks() == 0) {
+        sp<ThreadBase> thread = mThread.promote();
+        if (thread != 0) {
+            size_t numSamples = thread->frameCount() * thread->channelCount();
+            memset(mInBuffer, 0, numSamples * sizeof(int16_t));
+        }
+    }
+}
+
+status_t AudioFlinger::EffectChain::addEffect(sp<EffectModule>& effect)
+{
+    effect_descriptor_t desc = effect->desc();
+    uint32_t insertPref = desc.flags & EFFECT_FLAG_INSERT_MASK;
+
+    Mutex::Autolock _l(mLock);
+
+    if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+        // Auxiliary effects are inserted at the beginning of mEffects vector as
+        // they are processed first and accumulated in chain input buffer
+        mEffects.insertAt(effect, 0);
+        sp<ThreadBase> thread = mThread.promote();
+        if (thread == 0) {
+            return NO_INIT;
+        }
+        // the input buffer for auxiliary effect contains mono samples in
+        // 32 bit format. This is to avoid saturation in AudoMixer
+        // accumulation stage. Saturation is done in EffectModule::process() before
+        // calling the process in effect engine
+        size_t numSamples = thread->frameCount();
+        int32_t *buffer = new int32_t[numSamples];
+        memset(buffer, 0, numSamples * sizeof(int32_t));
+        effect->setInBuffer((int16_t *)buffer);
+        // auxiliary effects output samples to chain input buffer for further processing
+        // by insert effects
+        effect->setOutBuffer(mInBuffer);
+    } else {
+        // Insert effects are inserted at the end of mEffects vector as they are processed
+        //  after track and auxiliary effects.
+        // Insert effect order:
+        //  if EFFECT_FLAG_INSERT_FIRST or EFFECT_FLAG_INSERT_EXCLUSIVE insert as first insert effect
+        //  else if EFFECT_FLAG_INSERT_ANY insert after first or before last
+        //  else insert as last insert effect
+        // Reject insertion if:
+        //  - EFFECT_FLAG_INSERT_EXCLUSIVE and another effect is present
+        //  - an effect with EFFECT_FLAG_INSERT_EXCLUSIVE is present
+        //  - EFFECT_FLAG_INSERT_FIRST or EFFECT_FLAG_INSERT_LAST and an effect with same
+        //  preference is present
+
+        int size = (int)mEffects.size();
+        int idx_insert = size;
+        int idx_insert_first = -1;
+        int idx_insert_last = -1;
+
+        for (int i = 0; i < size; i++) {
+            effect_descriptor_t d = mEffects[i]->desc();
+            uint32_t iMode = d.flags & EFFECT_FLAG_TYPE_MASK;
+            uint32_t iPref = d.flags & EFFECT_FLAG_INSERT_MASK;
+            if (iMode == EFFECT_FLAG_TYPE_INSERT) {
+                // check invalid effect chaining combinations
+                if (insertPref == EFFECT_FLAG_INSERT_EXCLUSIVE ||
+                    iPref == EFFECT_FLAG_INSERT_EXCLUSIVE ||
+                    (insertPref != EFFECT_FLAG_INSERT_ANY
+                                && insertPref == iPref)) {
+                    return INVALID_OPERATION;
+                }
+                // remember position of first insert effect
+                if (idx_insert == size) {
+                    idx_insert = i;
+                }
+                // remember position of insert effect claiming
+                // first place
+                if (iPref == EFFECT_FLAG_INSERT_FIRST) {
+                    idx_insert_first = i;
+                }
+                // remember position of insert effect claiming
+                // last place
+                if (iPref == EFFECT_FLAG_INSERT_LAST) {
+                    idx_insert_last = i;
+                }
+            }
+        }
+
+        // modify idx_insert from first place if needed
+        if (idx_insert_first != -1) {
+            idx_insert = idx_insert_first + 1;
+        } else if (idx_insert_last != -1) {
+            idx_insert = idx_insert_last;
+        } else if (insertPref == EFFECT_FLAG_INSERT_LAST) {
+            idx_insert = size;
+        }
+
+        // always read samples from chain input buffer
+        effect->setInBuffer(mInBuffer);
+
+        // if last effect in the chain, output samples to chain
+        // output buffer, otherwise to chain input buffer
+        if (idx_insert == size) {
+            if (idx_insert != 0) {
+                mEffects[idx_insert-1]->setOutBuffer(mInBuffer);
+                mEffects[idx_insert-1]->configure();
+            }
+            effect->setOutBuffer(mOutBuffer);
+        } else {
+            effect->setOutBuffer(mInBuffer);
+        }
+        status_t status = mEffects.insertAt(effect, idx_insert);
+        // Always give volume control to last effect in chain with volume control capability
+        if (((desc.flags & EFFECT_FLAG_VOLUME_MASK) & EFFECT_FLAG_VOLUME_CTRL) &&
+                mVolumeCtrlIdx < idx_insert) {
+            mVolumeCtrlIdx = idx_insert;
+        }
+
+        LOGV("addEffect() effect %p, added in chain %p at rank %d status %d", effect.get(), this, idx_insert, status);
+    }
+    effect->configure();
+    return NO_ERROR;
+}
+
+size_t AudioFlinger::EffectChain::removeEffect(const sp<EffectModule>& effect)
+{
+    Mutex::Autolock _l(mLock);
+
+    int size = (int)mEffects.size();
+    int i;
+    uint32_t type = effect->desc().flags & EFFECT_FLAG_TYPE_MASK;
+
+    for (i = 0; i < size; i++) {
+        if (effect == mEffects[i]) {
+            if (type == EFFECT_FLAG_TYPE_AUXILIARY) {
+                delete[] effect->inBuffer();
+            } else {
+                if (i == size - 1 && i != 0) {
+                    mEffects[i - 1]->setOutBuffer(mOutBuffer);
+                    mEffects[i - 1]->configure();
+                }
+            }
+            mEffects.removeAt(i);
+            LOGV("removeEffect() effect %p, removed from chain %p at rank %d", effect.get(), this, i);
+            break;
+        }
+    }
+    // Return volume control to last effect in chain with volume control capability
+    if (mVolumeCtrlIdx == i) {
+        size = (int)mEffects.size();
+        for (i = size; i > 0; i--) {
+            if ((mEffects[i - 1]->desc().flags & EFFECT_FLAG_VOLUME_MASK) & EFFECT_FLAG_VOLUME_CTRL) {
+                break;
+            }
+        }
+        // mVolumeCtrlIdx reset to -1 if no effect found with volume control flag set
+        mVolumeCtrlIdx = i - 1;
+    }
+
+    return mEffects.size();
+}
+
+void AudioFlinger::EffectChain::setDevice(uint32_t device)
+{
+    size_t size = mEffects.size();
+    for (size_t i = 0; i < size; i++) {
+        mEffects[i]->setDevice(device);
+    }
+}
+
+bool AudioFlinger::EffectChain::setVolume(uint32_t *left, uint32_t *right)
+{
+    uint32_t newLeft = *left;
+    uint32_t newRight = *right;
+    bool hasControl = false;
+
+    // first get volume update from volume controller
+    if (mVolumeCtrlIdx >= 0) {
+        mEffects[mVolumeCtrlIdx]->setVolume(&newLeft, &newRight, true);
+        hasControl = true;
+    }
+    // then indicate volume to all other effects in chain.
+    // Pass altered volume to effects before volume controller
+    // and requested volume to effects after controller
+    uint32_t lVol = newLeft;
+    uint32_t rVol = newRight;
+    size_t size = mEffects.size();
+    for (size_t i = 0; i < size; i++) {
+        if ((int)i == mVolumeCtrlIdx) continue;
+        // this also works for mVolumeCtrlIdx == -1 when there is no volume controller
+        if ((int)i > mVolumeCtrlIdx) {
+            lVol = *left;
+            rVol = *right;
+        }
+        mEffects[i]->setVolume(&lVol, &rVol, false);
+    }
+    *left = newLeft;
+    *right = newRight;
+
+    return hasControl;
+}
+
+sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getVolumeController()
+{
+    sp<EffectModule> effect;
+    if (mVolumeCtrlIdx >= 0) {
+        effect = mEffects[mVolumeCtrlIdx];
+    }
+    return effect;
+}
+
+
+status_t AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "Effects for session %d:\n", mSessionId);
+    result.append(buffer);
+
+    bool locked = tryLock(mLock);
+    // failed to lock - AudioFlinger is probably deadlocked
+    if (!locked) {
+        result.append("\tCould not lock mutex:\n");
+    }
+
+    result.append("\tNum fx In buffer   Out buffer   Vol ctrl Active tracks:\n");
+    snprintf(buffer, SIZE, "\t%02d     0x%08x  0x%08x   %02d       %d\n",
+            mEffects.size(),
+            (uint32_t)mInBuffer,
+            (uint32_t)mOutBuffer,
+            (mVolumeCtrlIdx == -1) ? 0 : mEffects[mVolumeCtrlIdx]->id(),
+            mActiveTrackCnt);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+
+    for (size_t i = 0; i < mEffects.size(); ++i) {
+        sp<EffectModule> effect = mEffects[i];
+        if (effect != 0) {
+            effect->dump(fd, args);
+        }
+    }
+
+    if (locked) {
+        mLock.unlock();
+    }
+
+    return NO_ERROR;
+}
+
+#undef LOG_TAG
+#define LOG_TAG "AudioFlinger"
+
 // ----------------------------------------------------------------------------
 
 status_t AudioFlinger::onTransact(
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index f35f38b..e543334 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -42,6 +42,7 @@
 namespace android {
 
 class audio_track_cblk_t;
+class effect_param_cblk_t;
 class AudioMixer;
 class AudioBuffer;
 class AudioResampler;
@@ -75,6 +76,7 @@
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 int output,
+                                int *sessionId,
                                 status_t *status);
 
     virtual     uint32_t    sampleRate(int output) const;
@@ -139,6 +141,28 @@
 
     virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output);
 
+    virtual int newAudioSessionId();
+
+    virtual status_t loadEffectLibrary(const char *libPath, int *handle);
+
+    virtual status_t unloadEffectLibrary(int handle);
+
+    virtual status_t queryNumberEffects(uint32_t *numEffects);
+
+    virtual status_t queryNextEffect(effect_descriptor_t *descriptor);
+
+    virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor);
+
+    virtual sp<IEffect> createEffect(pid_t pid,
+                        effect_descriptor_t *pDesc,
+                        const sp<IEffectClient>& effectClient,
+                        int32_t priority,
+                        int output,
+                        int sessionId,
+                        status_t *status,
+                        int *id,
+                        int *enabled);
+
     enum hardware_call_state {
         AUDIO_HW_IDLE = 0,
         AUDIO_HW_INIT,
@@ -167,6 +191,7 @@
                                 int channelCount,
                                 int frameCount,
                                 uint32_t flags,
+                                int *sessionId,
                                 status_t *status);
 
     virtual     status_t    onTransact(
@@ -233,6 +258,9 @@
     class DuplicatingThread;
     class Track;
     class RecordTrack;
+    class EffectModule;
+    class EffectHandle;
+    class EffectChain;
 
     class ThreadBase : public Thread {
     public:
@@ -268,13 +296,15 @@
                                         int channelCount,
                                         int frameCount,
                                         uint32_t flags,
-                                        const sp<IMemory>& sharedBuffer);
+                                        const sp<IMemory>& sharedBuffer,
+                                        int sessionId);
                                 ~TrackBase();
 
             virtual status_t    start() = 0;
             virtual void        stop() = 0;
                     sp<IMemory> getCblk() const;
                     audio_track_cblk_t* cblk() const { return mCblk; }
+                    int         sessionId() { return mSessionId; }
 
         protected:
             friend class ThreadBase;
@@ -323,6 +353,7 @@
             int                 mClientTid;
             uint8_t             mFormat;
             uint32_t            mFlags;
+            int                 mSessionId;
         };
 
         class ConfigEvent {
@@ -405,7 +436,8 @@
                                         int format,
                                         int channelCount,
                                         int frameCount,
-                                        const sp<IMemory>& sharedBuffer);
+                                        const sp<IMemory>& sharedBuffer,
+                                        int sessionId);
                                 ~Track();
 
                     void        dump(char* buffer, size_t size);
@@ -424,6 +456,12 @@
                     int type() const {
                         return mStreamType;
                     }
+                    status_t    attachAuxEffect(int EffectId);
+                    void        setAuxBuffer(int EffectId, int32_t *buffer);
+                    int32_t     *auxBuffer() { return mAuxBuffer; }
+                    void        setMainBuffer(int16_t *buffer) { mMainBuffer = buffer; }
+                    int16_t     *mainBuffer() { return mMainBuffer; }
+                    int         auxEffectId() { return mAuxEffectId; }
 
 
         protected:
@@ -464,6 +502,9 @@
             bool                mResetDone;
             int                 mStreamType;
             int                 mName;
+            int16_t             *mMainBuffer;
+            int32_t             *mAuxBuffer;
+            int                 mAuxEffectId;
         };  // end of Track
 
 
@@ -505,7 +546,7 @@
             DuplicatingThread*          mSourceThread;
         };  // end of OutputTrack
 
-        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
+        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
         virtual             ~PlaybackThread();
 
         virtual     status_t    dump(int fd, const Vector<String16>& args);
@@ -538,6 +579,7 @@
                                     int channelCount,
                                     int frameCount,
                                     const sp<IMemory>& sharedBuffer,
+                                    int sessionId,
                                     status_t *status);
 
                     AudioStreamOut* getOutput() { return mOutput; }
@@ -549,6 +591,29 @@
         virtual     String8     getParameters(const String8& keys);
         virtual     void        audioConfigChanged_l(int event, int param = 0);
         virtual     status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
+                    int16_t     *mixBuffer() { return mMixBuffer; };
+
+                    sp<EffectHandle> createEffect_l(
+                                        const sp<AudioFlinger::Client>& client,
+                                        const sp<IEffectClient>& effectClient,
+                                        int32_t priority,
+                                        int sessionId,
+                                        effect_descriptor_t *desc,
+                                        int *enabled,
+                                        status_t *status);
+
+                    bool hasAudioSession(int sessionId);
+                    sp<EffectChain> getEffectChain(int sessionId);
+                    sp<EffectChain> getEffectChain_l(int sessionId);
+                    status_t addEffectChain_l(const sp<EffectChain>& chain);
+                    size_t removeEffectChain_l(const sp<EffectChain>& chain);
+                    void lockEffectChains_l();
+                    void unlockEffectChains();
+
+                    sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId);
+                    void detachAuxEffect_l(int effectId);
+                    status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);
+                    status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);
 
         struct  stream_type_t {
             stream_type_t()
@@ -591,8 +656,11 @@
 
         void        readOutputParameters();
 
+        uint32_t    device() { return mDevice; }
+
         virtual status_t    dumpInternals(int fd, const Vector<String16>& args);
         status_t    dumpTracks(int fd, const Vector<String16>& args);
+        status_t    dumpEffectChains(int fd, const Vector<String16>& args);
 
         SortedVector< sp<Track> >       mTracks;
         // mStreamTypes[] uses 1 additionnal stream type internally for the OutputTrack used by DuplicatingThread
@@ -603,11 +671,13 @@
         int                             mNumWrites;
         int                             mNumDelayedWrites;
         bool                            mInWrite;
+        Vector< sp<EffectChain> >       mEffectChains;
+        uint32_t                        mDevice;
     };
 
     class MixerThread : public PlaybackThread {
     public:
-        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
+        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
         virtual             ~MixerThread();
 
         // Thread virtuals
@@ -630,7 +700,7 @@
     class DirectOutputThread : public PlaybackThread {
     public:
 
-        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
+        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
         ~DirectOutputThread();
 
         // Thread virtuals
@@ -645,8 +715,12 @@
         virtual     uint32_t    idleSleepTimeUs();
 
     private:
-        float mLeftVolume;
-        float mRightVolume;
+        void applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp);
+
+        float mLeftVolFloat;
+        float mRightVolFloat;
+        uint16_t mLeftVolShort;
+        uint16_t mRightVolShort;
     };
 
     class DuplicatingThread : public MixerThread {
@@ -676,6 +750,8 @@
               float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
               void audioConfigChanged_l(int event, int ioHandle, void *param2);
 
+              int  nextUniqueId();
+
     friend class AudioBuffer;
 
     class TrackHandle : public android::BnAudioTrack {
@@ -689,6 +765,7 @@
         virtual void        pause();
         virtual void        setVolume(float left, float right);
         virtual sp<IMemory> getCblk() const;
+        virtual status_t    attachAuxEffect(int effectId);
         virtual status_t onTransact(
             uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
     private:
@@ -717,7 +794,8 @@
                                         int format,
                                         int channelCount,
                                         int frameCount,
-                                        uint32_t flags);
+                                        uint32_t flags,
+                                        int sessionId);
                                 ~RecordTrack();
 
             virtual status_t    start();
@@ -792,6 +870,215 @@
         sp<RecordThread::RecordTrack> mRecordTrack;
     };
 
+    //--- Audio Effect Management
+
+    // EffectModule and EffectChain classes both have their own mutex to protect
+    // state changes or resource modifications. Always respect the following order
+    // if multiple mutexes must be acquired to avoid cross deadlock:
+    // AudioFlinger -> ThreadBase -> EffectChain -> EffectModule
+
+    // The EffectModule class is a wrapper object controlling the effect engine implementation
+    // in the effect library. It prevents concurrent calls to process() and command() functions
+    // from different client threads. It keeps a list of EffectHandle objects corresponding
+    // to all client applications using this effect and notifies applications of effect state,
+    // control or parameter changes. It manages the activation state machine to send appropriate
+    // reset, enable, disable commands to effect engine and provide volume
+    // ramping when effects are activated/deactivated.
+    // When controlling an auxiliary effect, the EffectModule also provides an input buffer used by
+    // the attached track(s) to accumulate their auxiliary channel.
+    class EffectModule: public RefBase {
+    public:
+        EffectModule(const wp<ThreadBase>& wThread,
+                        const wp<AudioFlinger::EffectChain>& chain,
+                        effect_descriptor_t *desc,
+                        int id,
+                        int sessionId);
+        ~EffectModule();
+
+        enum effect_state {
+            IDLE,
+            RESET,
+            STARTING,
+            ACTIVE,
+            STOPPING,
+            STOPPED
+        };
+
+        int         id() { return mId; }
+        void process();
+        status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);
+
+        void reset();
+        status_t configure();
+        status_t init();
+        uint32_t state() {
+            return mState;
+        }
+        uint32_t status() {
+            return mStatus;
+        }
+        status_t    setEnabled(bool enabled);
+        bool isEnabled();
+
+        void        setInBuffer(int16_t *buffer) { mConfig.inputCfg.buffer.s16 = buffer; }
+        int16_t     *inBuffer() { return mConfig.inputCfg.buffer.s16; }
+        void        setOutBuffer(int16_t *buffer) { mConfig.outputCfg.buffer.s16 = buffer; }
+        int16_t     *outBuffer() { return mConfig.outputCfg.buffer.s16; }
+
+        status_t addHandle(sp<EffectHandle>& handle);
+        void disconnect(const wp<EffectHandle>& handle);
+        size_t removeHandle (const wp<EffectHandle>& handle);
+
+        effect_descriptor_t& desc() { return mDescriptor; }
+
+        status_t         setDevice(uint32_t device);
+        status_t         setVolume(uint32_t *left, uint32_t *right, bool controller);
+
+        status_t         dump(int fd, const Vector<String16>& args);
+
+    protected:
+
+        EffectModule(const EffectModule&);
+        EffectModule& operator = (const EffectModule&);
+
+        status_t start();
+        status_t stop();
+
+        Mutex               mLock;      // mutex for process, commands and handles list protection
+        wp<ThreadBase>      mThread;    // parent thread
+        wp<EffectChain>     mChain;     // parent effect chain
+        int                 mId;        // this instance unique ID
+        int                 mSessionId; // audio session ID
+        effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
+        effect_config_t     mConfig;    // input and output audio configuration
+        effect_interface_t  mEffectInterface; // Effect module C API
+        status_t mStatus;               // initialization status
+        uint32_t mState;                // current activation state (effect_state)
+        Vector< wp<EffectHandle> > mHandles;    // list of client handles
+    };
+
+    // The EffectHandle class implements the IEffect interface. It provides resources
+    // to receive parameter updates, keeps track of effect control
+    // ownership and state and has a pointer to the EffectModule object it is controlling.
+    // There is one EffectHandle object for each application controlling (or using)
+    // an effect module.
+    // The EffectHandle is obtained by calling AudioFlinger::createEffect().
+    class EffectHandle: public android::BnEffect {
+    public:
+
+        EffectHandle(const sp<EffectModule>& effect,
+                const sp<AudioFlinger::Client>& client,
+                const sp<IEffectClient>& effectClient,
+                int32_t priority);
+        virtual ~EffectHandle();
+
+        // IEffect
+        virtual status_t enable();
+        virtual status_t disable();
+        virtual status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);
+        virtual void disconnect();
+        virtual sp<IMemory> getCblk() const;
+        virtual status_t onTransact(uint32_t code, const Parcel& data,
+                Parcel* reply, uint32_t flags);
+
+
+        // Give or take control of effect module
+        void setControl(bool hasControl, bool signal);
+        void commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData);
+        void setEnabled(bool enabled);
+
+        // Getters
+        int id() { return mEffect->id(); }
+        int priority() { return mPriority; }
+        bool hasControl() { return mHasControl; }
+        sp<EffectModule> effect() { return mEffect; }
+
+        void dump(char* buffer, size_t size);
+
+    protected:
+
+        EffectHandle(const EffectHandle&);
+        EffectHandle& operator =(const EffectHandle&);
+
+        sp<EffectModule> mEffect;           // pointer to controlled EffectModule
+        sp<IEffectClient> mEffectClient;    // callback interface for client notifications
+        sp<Client>          mClient;        // client for shared memory allocation
+        sp<IMemory>         mCblkMemory;    // shared memory for control block
+        effect_param_cblk_t* mCblk;         // control block for deferred parameter setting via shared memory
+        uint8_t*            mBuffer;        // pointer to parameter area in shared memory
+        int mPriority;                      // client application priority to control the effect
+        bool mHasControl;                   // true if this handle is controlling the effect
+    };
+
+    // the EffectChain class represents a group of effects associated to one audio session.
+    // There can be any number of EffectChain objects per output mixer thread (PlaybackThread).
+    // The EffecChain with session ID 0 contains global effects applied to the output mix.
+    // Effects in this chain can be insert or auxiliary. Effects in other chains (attached to tracks)
+    // are insert only. The EffectChain maintains an ordered list of effect module, the order corresponding
+    // in the effect process order. When attached to a track (session ID != 0), it also provide it's own
+    // input buffer used by the track as accumulation buffer.
+    class EffectChain: public RefBase {
+    public:
+        EffectChain(const wp<ThreadBase>& wThread, int sessionId);
+        ~EffectChain();
+
+        void process_l();
+
+        void lock() {
+            mLock.lock();
+        }
+        void unlock() {
+            mLock.unlock();
+        }
+
+        status_t addEffect(sp<EffectModule>& handle);
+        size_t removeEffect(const sp<EffectModule>& handle);
+
+        int sessionId() {
+            return mSessionId;
+        }
+        sp<EffectModule> getEffectFromDesc(effect_descriptor_t *descriptor);
+        sp<EffectModule> getEffectFromId(int id);
+        sp<EffectModule> getVolumeController();
+        bool setVolume(uint32_t *left, uint32_t *right);
+        void setDevice(uint32_t device);
+
+        void setInBuffer(int16_t *buffer, bool ownsBuffer = false) {
+            mInBuffer = buffer;
+            mOwnInBuffer = ownsBuffer;
+        }
+        int16_t *inBuffer() {
+            return mInBuffer;
+        }
+        void setOutBuffer(int16_t *buffer) {
+            mOutBuffer = buffer;
+        }
+        int16_t *outBuffer() {
+            return mOutBuffer;
+        }
+
+        void startTrack() {mActiveTrackCnt++;}
+        void stopTrack() {mActiveTrackCnt--;}
+        int activeTracks() { return mActiveTrackCnt;}
+
+        status_t dump(int fd, const Vector<String16>& args);
+
+    protected:
+
+        EffectChain(const EffectChain&);
+        EffectChain& operator =(const EffectChain&);
+
+        wp<ThreadBase> mThread;     // parent mixer thread
+        Mutex mLock;                // mutex protecting effect list
+        Vector<sp<EffectModule> > mEffects; // list of effect modules
+        int mSessionId;             // audio session ID
+        int16_t *mInBuffer;         // chain input buffer
+        int16_t *mOutBuffer;        // chain output buffer
+        int mVolumeCtrlIdx;         // index of insert effect having control over volume
+        int mActiveTrackCnt;        // number of active tracks connected
+        bool mOwnInBuffer;          // true if the chain owns its input buffer
+    };
+
     friend class RecordThread;
     friend class PlaybackThread;
 
@@ -813,7 +1100,7 @@
                 DefaultKeyedVector< int, sp<RecordThread> >    mRecordThreads;
 
                 DefaultKeyedVector< pid_t, sp<NotificationClient> >    mNotificationClients;
-                int                                 mNextThreadId;
+                volatile int32_t                    mNextUniqueId;
 #ifdef LVMX
                 int mLifeVibesClientPid;
 #endif
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
index 19a442a..8aaa325 100644
--- a/libs/audioflinger/AudioMixer.cpp
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -56,6 +56,8 @@
         t->volume[1] = UNITY_GAIN;
         t->volumeInc[0] = 0;
         t->volumeInc[1] = 0;
+        t->auxLevel = 0;
+        t->auxInc = 0;
         t->channelCount = 2;
         t->enabled = 0;
         t->format = 16;
@@ -65,6 +67,8 @@
         t->resampler = 0;
         t->sampleRate = mSampleRate;
         t->in = 0;
+        t->mainBuffer = NULL;
+        t->auxBuffer = NULL;
         t++;
     }
 }
@@ -169,28 +173,48 @@
     return NO_ERROR;
 }
 
-status_t AudioMixer::setParameter(int target, int name, int value)
+status_t AudioMixer::setParameter(int target, int name, void *value)
 {
+    int valueInt = (int)value;
+    int32_t *valueBuf = (int32_t *)value;
+
     switch (target) {
     case TRACK:
         if (name == CHANNEL_COUNT) {
-            if ((uint32_t(value) <= MAX_NUM_CHANNELS) && (value)) {
-                if (mState.tracks[ mActiveTrack ].channelCount != value) {
-                    mState.tracks[ mActiveTrack ].channelCount = value;
-                    LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", value);
+            if ((uint32_t(valueInt) <= MAX_NUM_CHANNELS) && (valueInt)) {
+                if (mState.tracks[ mActiveTrack ].channelCount != valueInt) {
+                    mState.tracks[ mActiveTrack ].channelCount = valueInt;
+                    LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", valueInt);
                     invalidateState(1<<mActiveTrack);
                 }
                 return NO_ERROR;
             }
         }
+        if (name == MAIN_BUFFER) {
+            if (mState.tracks[ mActiveTrack ].mainBuffer != valueBuf) {
+                mState.tracks[ mActiveTrack ].mainBuffer = valueBuf;
+                LOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf);
+                invalidateState(1<<mActiveTrack);
+            }
+            return NO_ERROR;
+        }
+        if (name == AUX_BUFFER) {
+            if (mState.tracks[ mActiveTrack ].auxBuffer != valueBuf) {
+                mState.tracks[ mActiveTrack ].auxBuffer = valueBuf;
+                LOGV("setParameter(TRACK, AUX_BUFFER, %p)", valueBuf);
+                invalidateState(1<<mActiveTrack);
+            }
+            return NO_ERROR;
+        }
+
         break;
     case RESAMPLE:
         if (name == SAMPLE_RATE) {
-            if (value > 0) {
+            if (valueInt > 0) {
                 track_t& track = mState.tracks[ mActiveTrack ];
-                if (track.setResampler(uint32_t(value), mSampleRate)) {
+                if (track.setResampler(uint32_t(valueInt), mSampleRate)) {
                     LOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)",
-                            uint32_t(value));
+                            uint32_t(valueInt));
                     invalidateState(1<<mActiveTrack);
                 }
                 return NO_ERROR;
@@ -201,18 +225,39 @@
     case VOLUME:
         if ((uint32_t(name-VOLUME0) < MAX_NUM_CHANNELS)) {
             track_t& track = mState.tracks[ mActiveTrack ];
-            if (track.volume[name-VOLUME0] != value) {
+            if (track.volume[name-VOLUME0] != valueInt) {
+                LOGV("setParameter(VOLUME, VOLUME0/1: %04x)", valueInt);
                 track.prevVolume[name-VOLUME0] = track.volume[name-VOLUME0] << 16;
-                track.volume[name-VOLUME0] = value;
+                track.volume[name-VOLUME0] = valueInt;
                 if (target == VOLUME) {
-                    track.prevVolume[name-VOLUME0] = value << 16;
+                    track.prevVolume[name-VOLUME0] = valueInt << 16;
                     track.volumeInc[name-VOLUME0] = 0;
                 } else {
-                    int32_t d = (value<<16) - track.prevVolume[name-VOLUME0];
+                    int32_t d = (valueInt<<16) - track.prevVolume[name-VOLUME0];
                     int32_t volInc = d / int32_t(mState.frameCount);
                     track.volumeInc[name-VOLUME0] = volInc;
                     if (volInc == 0) {
-                        track.prevVolume[name-VOLUME0] = value << 16;
+                        track.prevVolume[name-VOLUME0] = valueInt << 16;
+                    }
+                }
+                invalidateState(1<<mActiveTrack);
+            }
+            return NO_ERROR;
+        } else if (name == AUXLEVEL) {
+            track_t& track = mState.tracks[ mActiveTrack ];
+            if (track.auxLevel != valueInt) {
+                LOGV("setParameter(VOLUME, AUXLEVEL: %04x)", valueInt);
+                track.prevAuxLevel = track.auxLevel << 16;
+                track.auxLevel = valueInt;
+                if (target == VOLUME) {
+                    track.prevAuxLevel = valueInt << 16;
+                    track.auxInc = 0;
+                } else {
+                    int32_t d = (valueInt<<16) - track.prevAuxLevel;
+                    int32_t volInc = d / int32_t(mState.frameCount);
+                    track.auxInc = volInc;
+                    if (volInc == 0) {
+                        track.prevAuxLevel = valueInt << 16;
                     }
                 }
                 invalidateState(1<<mActiveTrack);
@@ -245,7 +290,7 @@
 }
 
 inline
-void AudioMixer::track_t::adjustVolumeRamp()
+void AudioMixer::track_t::adjustVolumeRamp(bool aux)
 {
     for (int i=0 ; i<2 ; i++) {
         if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) ||
@@ -254,6 +299,13 @@
             prevVolume[i] = volume[i]<<16;
         }
     }
+    if (aux) {
+        if (((auxInc>0) && (((prevAuxLevel+auxInc)>>16) >= auxLevel)) ||
+            ((auxInc<0) && (((prevAuxLevel+auxInc)>>16) <= auxLevel))) {
+            auxInc = 0;
+            prevAuxLevel = auxLevel<<16;
+        }
+    }
 }
 
 
@@ -265,13 +317,13 @@
 
 
 
-void AudioMixer::process(void* output)
+void AudioMixer::process()
 {
-    mState.hook(&mState, output);
+    mState.hook(&mState);
 }
 
 
-void AudioMixer::process__validate(state_t* state, void* output)
+void AudioMixer::process__validate(state_t* state)
 {
     LOGW_IF(!state->needsChanged,
         "in process__validate() but nothing's invalid");
@@ -308,7 +360,10 @@
         n |= NEEDS_CHANNEL_1 + t.channelCount - 1;
         n |= NEEDS_FORMAT_16;
         n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED;
-       
+        if (t.auxLevel != 0 && t.auxBuffer != NULL) {
+            n |= NEEDS_AUX_ENABLED;
+        }
+
         if (t.volumeInc[0]|t.volumeInc[1]) {
             volumeRamp = 1;
         } else if (!t.doesResample() && t.volumeRL == 0) {
@@ -319,6 +374,9 @@
         if ((n & NEEDS_MUTE__MASK) == NEEDS_MUTE_ENABLED) {
             t.hook = track__nop;
         } else {
+            if ((n & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
+                all16BitsStereoNoResample = 0;
+            }
             if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
                 all16BitsStereoNoResample = 0;
                 resampling = 1;
@@ -369,7 +427,7 @@
         countActiveTracks, state->enabledTracks,
         all16BitsStereoNoResample, resampling, volumeRamp);
 
-   state->hook(state, output);
+   state->hook(state);
 
    // Now that the volume ramp has been done, set optimal state and
    // track hooks for subsequent mixer process
@@ -390,7 +448,7 @@
        }
        if (allMuted) {
            state->hook = process__nop;
-       } else if (!resampling && all16BitsStereoNoResample) {
+       } else if (all16BitsStereoNoResample) {
            if (countActiveTracks == 1) {
               state->hook = process__OneTrack16BitsStereoNoResampling;
            }
@@ -481,30 +539,44 @@
 }
 
 
-void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux)
 {
     t->resampler->setSampleRate(t->sampleRate);
 
     // ramp gain - resample to temp buffer and scale/mix in 2nd step
-    if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+    if (aux != NULL) {
+        // always resample with unity gain when sending to auxiliary buffer to be able
+        // to apply send level after resampling
+        // TODO: modify each resampler to support aux channel?
         t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
         memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
         t->resampler->resample(temp, outFrameCount, t->bufferProvider);
-        volumeRampStereo(t, out, outFrameCount, temp);
-    }
+        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
+            volumeRampStereo(t, out, outFrameCount, temp, aux);
+        } else {
+            volumeStereo(t, out, outFrameCount, temp, aux);
+        }
+    } else {
+        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+            t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
+            memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
+            t->resampler->resample(temp, outFrameCount, t->bufferProvider);
+            volumeRampStereo(t, out, outFrameCount, temp, aux);
+        }
 
-    // constant gain
-    else {
-        t->resampler->setVolume(t->volume[0], t->volume[1]);
-        t->resampler->resample(out, outFrameCount, t->bufferProvider);
+        // constant gain
+        else {
+            t->resampler->setVolume(t->volume[0], t->volume[1]);
+            t->resampler->resample(out, outFrameCount, t->bufferProvider);
+        }
     }
 }
 
-void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux)
 {
 }
 
-void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
 {
     int32_t vl = t->prevVolume[0];
     int32_t vr = t->prevVolume[1];
@@ -514,98 +586,238 @@
     //LOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
     //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
     //       (vl + vlInc*frameCount)/65536.0f, frameCount);
-   
+
     // ramp volume
-    do {
-        *out++ += (vl >> 16) * (*temp++ >> 12);
-        *out++ += (vr >> 16) * (*temp++ >> 12);
-        vl += vlInc;
-        vr += vrInc;
-    } while (--frameCount);
-
-    t->prevVolume[0] = vl;
-    t->prevVolume[1] = vr;
-    t->adjustVolumeRamp();
-}
-
-void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
-{
-    int16_t const *in = static_cast<int16_t const *>(t->in);
-
-    // ramp gain
-    if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
-        int32_t vl = t->prevVolume[0];
-        int32_t vr = t->prevVolume[1];
-        const int32_t vlInc = t->volumeInc[0];
-        const int32_t vrInc = t->volumeInc[1];
-
-        // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
-        //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
-        //        (vl + vlInc*frameCount)/65536.0f, frameCount);
+    if UNLIKELY(aux != NULL) {
+        int32_t va = t->prevAuxLevel;
+        const int32_t vaInc = t->auxInc;
+        int32_t l;
+        int32_t r;
 
         do {
-            *out++ += (vl >> 16) * (int32_t) *in++;
-            *out++ += (vr >> 16) * (int32_t) *in++;
+            l = (*temp++ >> 12);
+            r = (*temp++ >> 12);
+            *out++ += (vl >> 16) * l;
+            *out++ += (vr >> 16) * r;
+            *aux++ += (va >> 17) * (l + r);
+            vl += vlInc;
+            vr += vrInc;
+            va += vaInc;
+        } while (--frameCount);
+        t->prevAuxLevel = va;
+    } else {
+        do {
+            *out++ += (vl >> 16) * (*temp++ >> 12);
+            *out++ += (vr >> 16) * (*temp++ >> 12);
             vl += vlInc;
             vr += vrInc;
         } while (--frameCount);
-       
-        t->prevVolume[0] = vl;
-        t->prevVolume[1] = vr;
-        t->adjustVolumeRamp();
     }
+    t->prevVolume[0] = vl;
+    t->prevVolume[1] = vr;
+    t->adjustVolumeRamp((aux != NULL));
+}
 
-    // constant gain
-    else {
-        const uint32_t vrl = t->volumeRL;
+void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
+{
+    const int16_t vl = t->volume[0];
+    const int16_t vr = t->volume[1];
+
+    if UNLIKELY(aux != NULL) {
+        const int16_t va = (int16_t)t->auxLevel;
         do {
-            uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
-            in += 2;
-            out[0] = mulAddRL(1, rl, vrl, out[0]);
-            out[1] = mulAddRL(0, rl, vrl, out[1]);
+            int16_t l = (int16_t)(*temp++ >> 12);
+            int16_t r = (int16_t)(*temp++ >> 12);
+            out[0] = mulAdd(l, vl, out[0]);
+            int16_t a = (int16_t)(((int32_t)l + r) >> 1);
+            out[1] = mulAdd(r, vr, out[1]);
+            out += 2;
+            aux[0] = mulAdd(a, va, aux[0]);
+            aux++;
+        } while (--frameCount);
+    } else {
+        do {
+            int16_t l = (int16_t)(*temp++ >> 12);
+            int16_t r = (int16_t)(*temp++ >> 12);
+            out[0] = mulAdd(l, vl, out[0]);
+            out[1] = mulAdd(r, vr, out[1]);
             out += 2;
         } while (--frameCount);
     }
+}
+
+void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
+{
+    int16_t const *in = static_cast<int16_t const *>(t->in);
+
+    if UNLIKELY(aux != NULL) {
+        int32_t l;
+        int32_t r;
+        // ramp gain
+        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
+            int32_t vl = t->prevVolume[0];
+            int32_t vr = t->prevVolume[1];
+            int32_t va = t->prevAuxLevel;
+            const int32_t vlInc = t->volumeInc[0];
+            const int32_t vrInc = t->volumeInc[1];
+            const int32_t vaInc = t->auxInc;
+            // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+            //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
+            //        (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+            do {
+                l = (int32_t)*in++;
+                r = (int32_t)*in++;
+                *out++ += (vl >> 16) * l;
+                *out++ += (vr >> 16) * r;
+                *aux++ += (va >> 17) * (l + r);
+                vl += vlInc;
+                vr += vrInc;
+                va += vaInc;
+            } while (--frameCount);
+
+            t->prevVolume[0] = vl;
+            t->prevVolume[1] = vr;
+            t->prevAuxLevel = va;
+            t->adjustVolumeRamp(true);
+        }
+
+        // constant gain
+        else {
+            const uint32_t vrl = t->volumeRL;
+            const int16_t va = (int16_t)t->auxLevel;
+            do {
+                uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+                int16_t a = (int16_t)(((int32_t)in[0] + in[1]) >> 1);
+                in += 2;
+                out[0] = mulAddRL(1, rl, vrl, out[0]);
+                out[1] = mulAddRL(0, rl, vrl, out[1]);
+                out += 2;
+                aux[0] = mulAdd(a, va, aux[0]);
+                aux++;
+            } while (--frameCount);
+        }
+    } else {
+        // ramp gain
+        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+            int32_t vl = t->prevVolume[0];
+            int32_t vr = t->prevVolume[1];
+            const int32_t vlInc = t->volumeInc[0];
+            const int32_t vrInc = t->volumeInc[1];
+
+            // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+            //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
+            //        (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+            do {
+                *out++ += (vl >> 16) * (int32_t) *in++;
+                *out++ += (vr >> 16) * (int32_t) *in++;
+                vl += vlInc;
+                vr += vrInc;
+            } while (--frameCount);
+
+            t->prevVolume[0] = vl;
+            t->prevVolume[1] = vr;
+            t->adjustVolumeRamp(false);
+        }
+
+        // constant gain
+        else {
+            const uint32_t vrl = t->volumeRL;
+            do {
+                uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+                in += 2;
+                out[0] = mulAddRL(1, rl, vrl, out[0]);
+                out[1] = mulAddRL(0, rl, vrl, out[1]);
+                out += 2;
+            } while (--frameCount);
+        }
+    }
     t->in = in;
 }
 
-void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
 {
     int16_t const *in = static_cast<int16_t const *>(t->in);
 
-    // ramp gain
-    if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
-        int32_t vl = t->prevVolume[0];
-        int32_t vr = t->prevVolume[1];
-        const int32_t vlInc = t->volumeInc[0];
-        const int32_t vrInc = t->volumeInc[1];
+    if UNLIKELY(aux != NULL) {
+        // ramp gain
+        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
+            int32_t vl = t->prevVolume[0];
+            int32_t vr = t->prevVolume[1];
+            int32_t va = t->prevAuxLevel;
+            const int32_t vlInc = t->volumeInc[0];
+            const int32_t vrInc = t->volumeInc[1];
+            const int32_t vaInc = t->auxInc;
 
-        // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
-        //         t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
-        //         (vl + vlInc*frameCount)/65536.0f, frameCount);
+            // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+            //         t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
+            //         (vl + vlInc*frameCount)/65536.0f, frameCount);
 
-        do {
-            int32_t l = *in++;
-            *out++ += (vl >> 16) * l;
-            *out++ += (vr >> 16) * l;
-            vl += vlInc;
-            vr += vrInc;
-        } while (--frameCount);
-       
-        t->prevVolume[0] = vl;
-        t->prevVolume[1] = vr;
-        t->adjustVolumeRamp();
-    }
-    // constant gain
-    else {
-        const int16_t vl = t->volume[0];
-        const int16_t vr = t->volume[1];
-        do {
-            int16_t l = *in++;
-            out[0] = mulAdd(l, vl, out[0]);
-            out[1] = mulAdd(l, vr, out[1]);
-            out += 2;
-        } while (--frameCount);
+            do {
+                int32_t l = *in++;
+                *out++ += (vl >> 16) * l;
+                *out++ += (vr >> 16) * l;
+                *aux++ += (va >> 16) * l;
+                vl += vlInc;
+                vr += vrInc;
+                va += vaInc;
+            } while (--frameCount);
+
+            t->prevVolume[0] = vl;
+            t->prevVolume[1] = vr;
+            t->prevAuxLevel = va;
+            t->adjustVolumeRamp(true);
+        }
+        // constant gain
+        else {
+            const int16_t vl = t->volume[0];
+            const int16_t vr = t->volume[1];
+            const int16_t va = (int16_t)t->auxLevel;
+            do {
+                int16_t l = *in++;
+                out[0] = mulAdd(l, vl, out[0]);
+                out[1] = mulAdd(l, vr, out[1]);
+                out += 2;
+                aux[0] = mulAdd(l, va, aux[0]);
+                aux++;
+            } while (--frameCount);
+        }
+    } else {
+        // ramp gain
+        if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+            int32_t vl = t->prevVolume[0];
+            int32_t vr = t->prevVolume[1];
+            const int32_t vlInc = t->volumeInc[0];
+            const int32_t vrInc = t->volumeInc[1];
+
+            // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+            //         t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
+            //         (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+            do {
+                int32_t l = *in++;
+                *out++ += (vl >> 16) * l;
+                *out++ += (vr >> 16) * l;
+                vl += vlInc;
+                vr += vrInc;
+            } while (--frameCount);
+
+            t->prevVolume[0] = vl;
+            t->prevVolume[1] = vr;
+            t->adjustVolumeRamp(false);
+        }
+        // constant gain
+        else {
+            const int16_t vl = t->volume[0];
+            const int16_t vr = t->volume[1];
+            do {
+                int16_t l = *in++;
+                out[0] = mulAdd(l, vl, out[0]);
+                out[1] = mulAdd(l, vr, out[1]);
+                out += 2;
+            } while (--frameCount);
+        }
     }
     t->in = in;
 }
@@ -624,37 +836,56 @@
 }
 
 // no-op case
-void AudioMixer::process__nop(state_t* state, void* output)
+void AudioMixer::process__nop(state_t* state)
 {
-    // this assumes output 16 bits stereo, no resampling
-    memset(output, 0, state->frameCount*4);
-    uint32_t en = state->enabledTracks;
-    while (en) {
-        const int i = 31 - __builtin_clz(en);
-        en &= ~(1<<i);
-        track_t& t = state->tracks[i];
-        size_t outFrames = state->frameCount;
-        while (outFrames) {
-            t.buffer.frameCount = outFrames;
-            t.bufferProvider->getNextBuffer(&t.buffer);
-            if (!t.buffer.raw) break;
-            outFrames -= t.buffer.frameCount;
-            t.bufferProvider->releaseBuffer(&t.buffer);
+    uint32_t e0 = state->enabledTracks;
+    size_t bufSize = state->frameCount * sizeof(int16_t) * MAX_NUM_CHANNELS;
+    while (e0) {
+        // process by group of tracks with same output buffer to
+        // avoid multiple memset() on same buffer
+        uint32_t e1 = e0, e2 = e0;
+        int i = 31 - __builtin_clz(e1);
+        track_t& t1 = state->tracks[i];
+        e2 &= ~(1<<i);
+        while (e2) {
+            i = 31 - __builtin_clz(e2);
+            e2 &= ~(1<<i);
+            track_t& t2 = state->tracks[i];
+            if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
+                e1 &= ~(1<<i);
+            }
+        }
+        e0 &= ~(e1);
+
+        memset(t1.mainBuffer, 0, bufSize);
+
+        while (e1) {
+            i = 31 - __builtin_clz(e1);
+            e1 &= ~(1<<i);
+            t1 = state->tracks[i];
+            size_t outFrames = state->frameCount;
+            while (outFrames) {
+                t1.buffer.frameCount = outFrames;
+                t1.bufferProvider->getNextBuffer(&t1.buffer);
+                if (!t1.buffer.raw) break;
+                outFrames -= t1.buffer.frameCount;
+                t1.bufferProvider->releaseBuffer(&t1.buffer);
+            }
         }
     }
 }
 
 // generic code without resampling
-void AudioMixer::process__genericNoResampling(state_t* state, void* output)
+void AudioMixer::process__genericNoResampling(state_t* state)
 {
     int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
 
     // acquire each track's buffer
     uint32_t enabledTracks = state->enabledTracks;
-    uint32_t en = enabledTracks;
-    while (en) {
-        const int i = 31 - __builtin_clz(en);
-        en &= ~(1<<i);
+    uint32_t e0 = enabledTracks;
+    while (e0) {
+        const int i = 31 - __builtin_clz(e0);
+        e0 &= ~(1<<i);
         track_t& t = state->tracks[i];
         t.buffer.frameCount = state->frameCount;
         t.bufferProvider->getNextBuffer(&t.buffer);
@@ -666,110 +897,156 @@
             enabledTracks &= ~(1<<i);
     }
 
-    // this assumes output 16 bits stereo, no resampling
-    int32_t* out = static_cast<int32_t*>(output);
-    size_t numFrames = state->frameCount;
-    do {
-        memset(outTemp, 0, sizeof(outTemp));
-
-        en = enabledTracks;
-        while (en) {
-            const int i = 31 - __builtin_clz(en);
-            en &= ~(1<<i);
-            track_t& t = state->tracks[i];
-            size_t outFrames = BLOCKSIZE;
-           
-            while (outFrames) {
-                size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
-                if (inFrames) {
-                    (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp);
-                    t.frameCount -= inFrames;
-                    outFrames -= inFrames;
-                }
-                if (t.frameCount == 0 && outFrames) {
-                    t.bufferProvider->releaseBuffer(&t.buffer);
-                    t.buffer.frameCount = numFrames - (BLOCKSIZE - outFrames);
-                    t.bufferProvider->getNextBuffer(&t.buffer);
-                    t.in = t.buffer.raw;
-                    if (t.in == NULL) {
-                        enabledTracks &= ~(1<<i);
-                        break;
-                    }
-                    t.frameCount = t.buffer.frameCount;
-                 }
+    e0 = enabledTracks;
+    while (e0) {
+        // process by group of tracks with same output buffer to
+        // optimize cache use
+        uint32_t e1 = e0, e2 = e0;
+        int j = 31 - __builtin_clz(e1);
+        track_t& t1 = state->tracks[j];
+        e2 &= ~(1<<j);
+        while (e2) {
+            j = 31 - __builtin_clz(e2);
+            e2 &= ~(1<<j);
+            track_t& t2 = state->tracks[j];
+            if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
+                e1 &= ~(1<<j);
             }
         }
-
-        ditherAndClamp(out, outTemp, BLOCKSIZE);
-        out += BLOCKSIZE;
-        numFrames -= BLOCKSIZE;
-    } while (numFrames);
-
+        e0 &= ~(e1);
+        // this assumes output 16 bits stereo, no resampling
+        int32_t *out = t1.mainBuffer;
+        size_t numFrames = 0;
+        do {
+            memset(outTemp, 0, sizeof(outTemp));
+            e2 = e1;
+            while (e2) {
+                const int i = 31 - __builtin_clz(e2);
+                e2 &= ~(1<<i);
+                track_t& t = state->tracks[i];
+                size_t outFrames = BLOCKSIZE;
+                int32_t *aux = NULL;
+                if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
+                    aux = t.auxBuffer + numFrames;
+                }
+                while (outFrames) {
+                    size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
+                    if (inFrames) {
+                        (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, aux);
+                        t.frameCount -= inFrames;
+                        outFrames -= inFrames;
+                        if UNLIKELY(aux != NULL) {
+                            aux += inFrames;
+                        }
+                    }
+                    if (t.frameCount == 0 && outFrames) {
+                        t.bufferProvider->releaseBuffer(&t.buffer);
+                        t.buffer.frameCount = (state->frameCount - numFrames) - (BLOCKSIZE - outFrames);
+                        t.bufferProvider->getNextBuffer(&t.buffer);
+                        t.in = t.buffer.raw;
+                        if (t.in == NULL) {
+                            enabledTracks &= ~(1<<i);
+                            e1 &= ~(1<<i);
+                            break;
+                        }
+                        t.frameCount = t.buffer.frameCount;
+                    }
+                }
+            }
+            ditherAndClamp(out, outTemp, BLOCKSIZE);
+            out += BLOCKSIZE;
+            numFrames += BLOCKSIZE;
+        } while (numFrames < state->frameCount);
+    }
 
     // release each track's buffer
-    en = enabledTracks;
-    while (en) {
-        const int i = 31 - __builtin_clz(en);
-        en &= ~(1<<i);
+    e0 = enabledTracks;
+    while (e0) {
+        const int i = 31 - __builtin_clz(e0);
+        e0 &= ~(1<<i);
         track_t& t = state->tracks[i];
         t.bufferProvider->releaseBuffer(&t.buffer);
     }
 }
 
-// generic code with resampling
-void AudioMixer::process__genericResampling(state_t* state, void* output)
+
+  // generic code with resampling
+void AudioMixer::process__genericResampling(state_t* state)
 {
     int32_t* const outTemp = state->outputTemp;
     const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount;
     memset(outTemp, 0, size);
 
-    int32_t* out = static_cast<int32_t*>(output);
     size_t numFrames = state->frameCount;
 
-    uint32_t en = state->enabledTracks;
-    while (en) {
-        const int i = 31 - __builtin_clz(en);
-        en &= ~(1<<i);
-        track_t& t = state->tracks[i];
-
-        // this is a little goofy, on the resampling case we don't
-        // acquire/release the buffers because it's done by
-        // the resampler.
-        if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
-            (t.hook)(&t, outTemp, numFrames, state->resampleTemp);
-        } else {
-
-            size_t outFrames = numFrames;
-           
-            while (outFrames) {
-                t.buffer.frameCount = outFrames;
-                t.bufferProvider->getNextBuffer(&t.buffer);
-                t.in = t.buffer.raw;
-                // t.in == NULL can happen if the track was flushed just after having
-                // been enabled for mixing.
-                if (t.in == NULL) break;
-
-                (t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp);
-                outFrames -= t.buffer.frameCount;
-                t.bufferProvider->releaseBuffer(&t.buffer);
+    uint32_t e0 = state->enabledTracks;
+    while (e0) {
+        // process by group of tracks with same output buffer
+        // to optimize cache use
+        uint32_t e1 = e0, e2 = e0;
+        int j = 31 - __builtin_clz(e1);
+        track_t& t1 = state->tracks[j];
+        e2 &= ~(1<<j);
+        while (e2) {
+            j = 31 - __builtin_clz(e2);
+            e2 &= ~(1<<j);
+            track_t& t2 = state->tracks[j];
+            if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
+                e1 &= ~(1<<j);
             }
         }
-    }
+        e0 &= ~(e1);
+        int32_t *out = t1.mainBuffer;
+        while (e1) {
+            const int i = 31 - __builtin_clz(e1);
+            e1 &= ~(1<<i);
+            track_t& t = state->tracks[i];
+            int32_t *aux = NULL;
+            if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
+                aux = t.auxBuffer;
+            }
 
-    ditherAndClamp(out, outTemp, numFrames);
+            // this is a little goofy, on the resampling case we don't
+            // acquire/release the buffers because it's done by
+            // the resampler.
+            if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
+                (t.hook)(&t, outTemp, numFrames, state->resampleTemp, aux);
+            } else {
+
+                size_t outFrames = 0;
+
+                while (outFrames < numFrames) {
+                    t.buffer.frameCount = numFrames - outFrames;
+                    t.bufferProvider->getNextBuffer(&t.buffer);
+                    t.in = t.buffer.raw;
+                    // t.in == NULL can happen if the track was flushed just after having
+                    // been enabled for mixing.
+                    if (t.in == NULL) break;
+
+                    if UNLIKELY(aux != NULL) {
+                        aux += outFrames;
+                    }
+                    (t.hook)(&t, outTemp + outFrames*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, aux);
+                    outFrames += t.buffer.frameCount;
+                    t.bufferProvider->releaseBuffer(&t.buffer);
+                }
+            }
+        }
+        ditherAndClamp(out, outTemp, numFrames);
+    }
 }
 
 // one track, 16 bits stereo without resampling is the most common case
-void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void* output)
+void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state)
 {
     const int i = 31 - __builtin_clz(state->enabledTracks);
     const track_t& t = state->tracks[i];
 
     AudioBufferProvider::Buffer& b(t.buffer);
-   
-    int32_t* out = static_cast<int32_t*>(output);
+
+    int32_t* out = t.mainBuffer;
     size_t numFrames = state->frameCount;
-  
+
     const int16_t vl = t.volume[0];
     const int16_t vr = t.volume[1];
     const uint32_t vrl = t.volumeRL;
@@ -787,7 +1064,7 @@
             return;
         }
         size_t outFrames = b.frameCount;
-       
+
         if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
             // volume is boosted, so we might need to clamp even though
             // we process only one track.
@@ -816,7 +1093,9 @@
 }
 
 // 2 tracks is also a common case
-void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output)
+// NEVER used in current implementation of process__validate()
+// only use if the 2 tracks have the same output buffer
+void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state)
 {
     int i;
     uint32_t en = state->enabledTracks;
@@ -829,24 +1108,25 @@
     i = 31 - __builtin_clz(en);
     const track_t& t1 = state->tracks[i];
     AudioBufferProvider::Buffer& b1(t1.buffer);
-   
+
     int16_t const *in0;
     const int16_t vl0 = t0.volume[0];
     const int16_t vr0 = t0.volume[1];
     size_t frameCount0 = 0;
-  
+
     int16_t const *in1;
     const int16_t vl1 = t1.volume[0];
     const int16_t vr1 = t1.volume[1];
     size_t frameCount1 = 0;
-   
-    int32_t* out = static_cast<int32_t*>(output);
+
+    //FIXME: only works if two tracks use same buffer
+    int32_t* out = t0.mainBuffer;
     size_t numFrames = state->frameCount;
     int16_t const *buff = NULL;
 
-  
+
     while (numFrames) {
-   
+
         if (frameCount0 == 0) {
             b0.frameCount = numFrames;
             t0.bufferProvider->getNextBuffer(&b0);
@@ -875,13 +1155,13 @@
             }
             frameCount1 = b1.frameCount;
         }
-       
+
         size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1;
 
         numFrames -= outFrames;
         frameCount0 -= outFrames;
         frameCount1 -= outFrames;
-       
+
         do {
             int32_t l0 = *in0++;
             int32_t r0 = *in0++;
@@ -896,17 +1176,17 @@
             r = clamp16(r);
             *out++ = (r<<16) | (l & 0xFFFF);
         } while (--outFrames);
-       
+
         if (frameCount0 == 0) {
             t0.bufferProvider->releaseBuffer(&b0);
         }
         if (frameCount1 == 0) {
             t1.bufferProvider->releaseBuffer(&b1);
         }
-    }   
-       
+    }
+
     if (buff != NULL) {
-        delete [] buff;       
+        delete [] buff;
     }
 }
 
diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h
index 15766cd..aee3e17 100644
--- a/libs/audioflinger/AudioMixer.h
+++ b/libs/audioflinger/AudioMixer.h
@@ -63,11 +63,14 @@
         // for target TRACK
         CHANNEL_COUNT   = 0x4000,
         FORMAT          = 0x4001,
+        MAIN_BUFFER     = 0x4002,
+        AUX_BUFFER      = 0x4003,
         // for TARGET RESAMPLE
         SAMPLE_RATE     = 0x4100,
         // for TARGET VOLUME (8 channels max)
         VOLUME0         = 0x4200,
         VOLUME1         = 0x4201,
+        AUXLEVEL        = 0x4210,
     };
 
 
@@ -78,10 +81,10 @@
     status_t    disable(int name);
 
     status_t    setActiveTrack(int track);
-    status_t    setParameter(int target, int name, int value);
+    status_t    setParameter(int target, int name, void *value);
 
     status_t    setBufferProvider(AudioBufferProvider* bufferProvider);
-    void        process(void* output);
+    void        process();
 
     uint32_t    trackNames() const { return mTrackNames; }
 
@@ -94,6 +97,7 @@
         NEEDS_FORMAT__MASK          = 0x000000F0,
         NEEDS_MUTE__MASK            = 0x00000100,
         NEEDS_RESAMPLE__MASK        = 0x00001000,
+        NEEDS_AUX__MASK             = 0x00010000,
     };
 
     enum {
@@ -107,6 +111,9 @@
 
         NEEDS_RESAMPLE_DISABLED     = 0x00000000,
         NEEDS_RESAMPLE_ENABLED      = 0x00001000,
+
+        NEEDS_AUX_DISABLED     = 0x00000000,
+        NEEDS_AUX_ENABLED      = 0x00010000,
     };
 
     static inline int32_t applyVolume(int32_t in, int32_t v) {
@@ -115,9 +122,10 @@
 
 
     struct state_t;
+    struct track_t;
 
-    typedef void (*mix_t)(state_t* state, void* output);
-
+    typedef void (*mix_t)(state_t* state);
+    typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux);
     static const int BLOCKSIZE = 16; // 4 cache lines
 
     struct track_t {
@@ -131,6 +139,9 @@
         int32_t     prevVolume[2];
 
         int32_t     volumeInc[2];
+        int32_t     auxLevel;
+        int32_t     auxInc;
+        int32_t     prevAuxLevel;
 
         uint16_t    frameCount;
 
@@ -142,15 +153,17 @@
         AudioBufferProvider*                bufferProvider;
         mutable AudioBufferProvider::Buffer buffer;
 
-        void (*hook)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp);
+        hook_t      hook;
         void const* in;             // current location in buffer
 
         AudioResampler*     resampler;
         uint32_t            sampleRate;
+        int32_t*           mainBuffer;
+        int32_t*           auxBuffer;
 
         bool        setResampler(uint32_t sampleRate, uint32_t devSampleRate);
         bool        doesResample() const;
-        void        adjustVolumeRamp();
+        void        adjustVolumeRamp(bool aux);
     };
 
     // pad to 32-bytes to fill cache line
@@ -173,18 +186,19 @@
 
     void invalidateState(uint32_t mask);
 
-    static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
-    static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
-    static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp);
-    static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
-    static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+    static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
+    static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
+    static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
+    static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
+    static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);
+    static void volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);
 
-    static void process__validate(state_t* state, void* output);
-    static void process__nop(state_t* state, void* output);
-    static void process__genericNoResampling(state_t* state, void* output);
-    static void process__genericResampling(state_t* state, void* output);
-    static void process__OneTrack16BitsStereoNoResampling(state_t* state, void* output);
-    static void process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output);
+    static void process__validate(state_t* state);
+    static void process__nop(state_t* state);
+    static void process__genericNoResampling(state_t* state);
+    static void process__genericResampling(state_t* state);
+    static void process__OneTrack16BitsStereoNoResampling(state_t* state);
+    static void process__TwoTracks16BitsStereoNoResampling(state_t* state);
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index e4d5bb3..1415493 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -71,6 +71,8 @@
 const char CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED[] = "smooth-zoom-supported";
 const char CameraParameters::KEY_FOCUS_DISTANCES[] = "focus-distances";
 const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format";
+const char CameraParameters::KEY_METERING_MODE[] = "metering-mode";
+const char CameraParameters::KEY_SUPPORTED_METERING_MODES[] = "metering-mode-values";
 
 const char CameraParameters::TRUE[] = "true";
 const char CameraParameters::FOCUS_DISTANCE_INFINITY[] = "Infinity";
@@ -142,6 +144,11 @@
 const char CameraParameters::FOCUS_MODE_EDOF[] = "edof";
 const char CameraParameters::FOCUS_MODE_CONTINUOUS[] = "continuous";
 
+// Values for metering mode settings.
+const char CameraParameters::METERING_MODE_CENTER_WEIGHTED[] = "center-weighted";
+const char CameraParameters::METERING_MODE_FRAME_AVERAGE[] = "frame-average";
+const char CameraParameters::METERING_MODE_SPOT[] = "spot";
+
 CameraParameters::CameraParameters()
                 : mMap()
 {
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index b8a0630..0879a66 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -14,7 +14,6 @@
     MessageQueue.cpp \
     SurfaceFlinger.cpp \
     TextureManager.cpp \
-    Tokenizer.cpp \
     Transform.cpp
 
 LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 3fbb4d3..a94fdd4 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -47,24 +47,16 @@
 
 // ---------------------------------------------------------------------------
 
-Layer::Layer(SurfaceFlinger* flinger, DisplayID display, 
-        const sp<Client>& client, int32_t i)
-    :   LayerBaseClient(flinger, display, client, i),
-        lcblk(NULL),
-        mSecure(false),
+Layer::Layer(SurfaceFlinger* flinger,
+        DisplayID display, const sp<Client>& client)
+    :   LayerBaseClient(flinger, display, client),
         mNeedsBlending(true),
         mNeedsDithering(false),
+        mSecure(false),
         mTextureManager(mFlags),
         mBufferManager(mTextureManager),
         mWidth(0), mHeight(0), mFixedSize(false)
 {
-    // no OpenGL operation is possible here, since we might not be
-    // in the OpenGL thread.
-    lcblk = new SharedBufferServer(
-            client->ctrlblk, i, mBufferManager.getDefaultBufferCount(),
-            getIdentity());
-
-   mBufferManager.setActiveBufferIndex( lcblk->getFrontBuffer() );
 }
 
 Layer::~Layer()
@@ -73,16 +65,46 @@
     EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
     mBufferManager.destroy(dpy);
 
-    // the actual buffers will be destroyed here
-    delete lcblk;
+    // we can use getUserClientUnsafe here because we know we're
+    // single-threaded at that point.
+    sp<UserClient> ourClient(mUserClientRef.getUserClientUnsafe());
+    if (ourClient != 0) {
+        ourClient->detachLayer(this);
+    }
+}
+
+status_t Layer::setToken(const sp<UserClient>& userClient,
+        SharedClient* sharedClient, int32_t token)
+{
+    SharedBufferServer* lcblk = new SharedBufferServer(
+            sharedClient, token, mBufferManager.getDefaultBufferCount(),
+            getIdentity());
+
+    status_t err = mUserClientRef.setToken(userClient, lcblk, token);
+    if (err != NO_ERROR) {
+        LOGE("ClientRef::setToken(%p, %p, %u) failed",
+                userClient.get(), lcblk, token);
+        delete lcblk;
+    }
+
+    return err;
+}
+
+int32_t Layer::getToken() const
+{
+    return mUserClientRef.getToken();
 }
 
 // called with SurfaceFlinger::mStateLock as soon as the layer is entered
 // in the purgatory list
 void Layer::onRemoved()
 {
-    // wake up the condition
-    lcblk->setStatus(NO_INIT);
+    ClientRef::Access sharedClient(mUserClientRef);
+    SharedBufferServer* lcblk(sharedClient.get());
+    if (lcblk) {
+        // wake up the condition
+        lcblk->setStatus(NO_INIT);
+    }
 }
 
 sp<LayerBaseClient::Surface> Layer::createSurface() const
@@ -140,7 +162,7 @@
     int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED);
     mNeedsDithering = layerRedsize > displayRedSize;
 
-    mSurface = new SurfaceLayer(mFlinger, clientIndex(), this);
+    mSurface = new SurfaceLayer(mFlinger, this);
     return NO_ERROR;
 }
 
@@ -225,10 +247,9 @@
 
 status_t Layer::setBufferCount(int bufferCount)
 {
-    // Ensures our client doesn't go away while we're accessing
-    // the shared area.
-    sp<Client> ourClient(client.promote());
-    if (ourClient == 0) {
+    ClientRef::Access sharedClient(mUserClientRef);
+    SharedBufferServer* lcblk(sharedClient.get());
+    if (!lcblk) {
         // oops, the client is already gone
         return DEAD_OBJECT;
     }
@@ -247,7 +268,7 @@
 {
     sp<GraphicBuffer> buffer;
 
-    if ((reqWidth | reqHeight | reqFormat) < 0)
+    if (int32_t(reqWidth | reqHeight | reqFormat) < 0)
         return buffer;
 
     if ((!reqWidth && reqHeight) || (reqWidth && !reqHeight))
@@ -255,8 +276,9 @@
 
     // this ensures our client doesn't go away while we're accessing
     // the shared area.
-    sp<Client> ourClient(client.promote());
-    if (ourClient == 0) {
+    ClientRef::Access sharedClient(mUserClientRef);
+    SharedBufferServer* lcblk(sharedClient.get());
+    if (!lcblk) {
         // oops, the client is already gone
         return buffer;
     }
@@ -391,8 +413,12 @@
             // a buffer, it'll get the new size.
             setBufferSize(temp.requested_w, temp.requested_h);
 
-            // all buffers need reallocation
-            lcblk->reallocateAll();
+            ClientRef::Access sharedClient(mUserClientRef);
+            SharedBufferServer* lcblk(sharedClient.get());
+            if (lcblk) {
+                // all buffers need reallocation
+                lcblk->reallocateAll();
+            }
         } else {
             // record the new size
             setBufferSize(temp.requested_w, temp.requested_h);
@@ -427,6 +453,14 @@
 
 void Layer::lockPageFlip(bool& recomputeVisibleRegions)
 {
+    ClientRef::Access sharedClient(mUserClientRef);
+    SharedBufferServer* lcblk(sharedClient.get());
+    if (!lcblk) {
+        // client died
+        recomputeVisibleRegions = true;
+        return;
+    }
+
     ssize_t buf = lcblk->retireAndLock();
     if (buf == NOT_ENOUGH_DATA) {
         // NOTE: This is not an error, it simply means there is nothing to
@@ -436,14 +470,14 @@
     }
 
     if (buf < NO_ERROR) {
-        LOGE("retireAndLock() buffer index (%d) out of range", buf);
+        LOGE("retireAndLock() buffer index (%d) out of range", int(buf));
         mPostedDirtyRegion.clear();
         return;
     }
 
     // we retired a buffer, which becomes the new front buffer
     if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) {
-        LOGE("retireAndLock() buffer index (%d) out of range", buf);
+        LOGE("retireAndLock() buffer index (%d) out of range", int(buf));
         mPostedDirtyRegion.clear();
         return;
     }
@@ -538,9 +572,17 @@
 
 void Layer::finishPageFlip()
 {
-    int buf = mBufferManager.getActiveBufferIndex();
-    status_t err = lcblk->unlock( buf );
-    LOGE_IF(err!=NO_ERROR, "layer %p, buffer=%d wasn't locked!", this, buf);
+    ClientRef::Access sharedClient(mUserClientRef);
+    SharedBufferServer* lcblk(sharedClient.get());
+    if (lcblk) {
+        int buf = mBufferManager.getActiveBufferIndex();
+        if (buf >= 0) {
+            status_t err = lcblk->unlock( buf );
+            LOGE_IF(err!=NO_ERROR,
+                    "layer %p, buffer=%d wasn't locked!",
+                    this, buf);
+        }
+    }
 }
 
 
@@ -548,8 +590,15 @@
 {
     LayerBaseClient::dump(result, buffer, SIZE);
 
-    SharedBufferStack::Statistics stats = lcblk->getStats();
-    result.append( lcblk->dump("      ") );
+    ClientRef::Access sharedClient(mUserClientRef);
+    SharedBufferServer* lcblk(sharedClient.get());
+    uint32_t totalTime = 0;
+    if (lcblk) {
+        SharedBufferStack::Statistics stats = lcblk->getStats();
+        totalTime= stats.totalTime;
+        result.append( lcblk->dump("      ") );
+    }
+
     sp<const GraphicBuffer> buf0(getBuffer(0));
     sp<const GraphicBuffer> buf1(getBuffer(1));
     uint32_t w0=0, h0=0, s0=0;
@@ -568,18 +617,59 @@
             "      "
             "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
             " freezeLock=%p, dq-q-time=%u us\n",
-            pixelFormat(),
-            w0, h0, s0, w1, h1, s1,
-            getFreezeLock().get(), stats.totalTime);
+            mFormat, w0, h0, s0, w1, h1, s1,
+            getFreezeLock().get(), totalTime);
 
     result.append(buffer);
 }
 
 // ---------------------------------------------------------------------------
 
+Layer::ClientRef::ClientRef()
+    : mToken(-1) {
+}
+
+Layer::ClientRef::~ClientRef() {
+    delete lcblk;
+}
+
+int32_t Layer::ClientRef::getToken() const {
+    Mutex::Autolock _l(mLock);
+    return mToken;
+}
+
+status_t Layer::ClientRef::setToken(const sp<UserClient>& uc,
+        SharedBufferServer* sharedClient, int32_t token) {
+    Mutex::Autolock _l(mLock);
+    if (mToken >= 0)
+        return INVALID_OPERATION;
+    mUserClient = uc;
+    mToken = token;
+    lcblk = sharedClient;
+    return NO_ERROR;
+}
+
+sp<UserClient> Layer::ClientRef::getUserClientUnsafe() const {
+    return mUserClient.promote();
+}
+
+// this class gives us access to SharedBufferServer safely
+// it makes sure the UserClient (and its associated shared memory)
+// won't go away while we're accessing it.
+Layer::ClientRef::Access::Access(const ClientRef& ref)
+    : lcblk(0)
+{
+    Mutex::Autolock _l(ref.mLock);
+    mUserClientStrongRef = ref.mUserClient.promote();
+    if (mUserClientStrongRef != 0)
+        lcblk = ref.lcblk;
+}
+
+// ---------------------------------------------------------------------------
+
 Layer::BufferManager::BufferManager(TextureManager& tm)
     : mNumBuffers(NUM_BUFFERS), mTextureManager(tm),
-      mActiveBuffer(0), mFailover(false)
+      mActiveBuffer(-1), mFailover(false)
 {
 }
 
@@ -600,7 +690,6 @@
 }
 
 status_t Layer::BufferManager::setActiveBufferIndex(size_t index) {
-    // TODO: need to validate 'index'
     mActiveBuffer = index;
     return NO_ERROR;
 }
@@ -611,7 +700,7 @@
 
 Texture Layer::BufferManager::getActiveTexture() const {
     Texture res;
-    if (mFailover) {
+    if (mFailover || mActiveBuffer<0) {
         res = mFailoverTexture;
     } else {
         static_cast<Image&>(res) = mBufferData[mActiveBuffer].texture;
@@ -620,10 +709,14 @@
 }
 
 sp<GraphicBuffer> Layer::BufferManager::getActiveBuffer() const {
-    const size_t activeBuffer = mActiveBuffer;
-    BufferData const * const buffers = mBufferData;
-    Mutex::Autolock _l(mLock);
-    return buffers[activeBuffer].buffer;
+    sp<GraphicBuffer> result;
+    const ssize_t activeBuffer = mActiveBuffer;
+    if (activeBuffer >= 0) {
+        BufferData const * const buffers = mBufferData;
+        Mutex::Autolock _l(mLock);
+        result = buffers[activeBuffer].buffer;
+    }
+    return result;
 }
 
 sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index)
@@ -667,19 +760,22 @@
 status_t Layer::BufferManager::initEglImage(EGLDisplay dpy,
         const sp<GraphicBuffer>& buffer)
 {
-    size_t index = mActiveBuffer;
-    Image& texture(mBufferData[index].texture);
-    status_t err = mTextureManager.initEglImage(&texture, dpy, buffer);
-    // if EGLImage fails, we switch to regular texture mode, and we
-    // free all resources associated with using EGLImages.
-    if (err == NO_ERROR) {
-        mFailover = false;
-        destroyTexture(&mFailoverTexture, dpy);
-    } else {
-        mFailover = true;
-        const size_t num = mNumBuffers;
-        for (size_t i=0 ; i<num ; i++) {
-            destroyTexture(&mBufferData[i].texture, dpy);
+    status_t err = NO_INIT;
+    ssize_t index = mActiveBuffer;
+    if (index >= 0) {
+        Image& texture(mBufferData[index].texture);
+        err = mTextureManager.initEglImage(&texture, dpy, buffer);
+        // if EGLImage fails, we switch to regular texture mode, and we
+        // free all resources associated with using EGLImages.
+        if (err == NO_ERROR) {
+            mFailover = false;
+            destroyTexture(&mFailoverTexture, dpy);
+        } else {
+            mFailover = true;
+            const size_t num = mNumBuffers;
+            for (size_t i=0 ; i<num ; i++) {
+                destroyTexture(&mBufferData[i].texture, dpy);
+            }
         }
     }
     return err;
@@ -707,8 +803,8 @@
 // ---------------------------------------------------------------------------
 
 Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger,
-        SurfaceID id, const sp<Layer>& owner)
-    : Surface(flinger, id, owner->getIdentity(), owner)
+        const sp<Layer>& owner)
+    : Surface(flinger, owner->getIdentity(), owner)
 {
 }
 
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
index 59603a5..d396ecf 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -38,6 +38,7 @@
 // ---------------------------------------------------------------------------
 
 class Client;
+class UserClient;
 class FreezeLock;
 
 // ---------------------------------------------------------------------------
@@ -45,21 +46,26 @@
 class Layer : public LayerBaseClient
 {
 public:
-    // lcblk is (almost) only accessed from the main SF thread, in the places
-    // where it's not, a reference to Client must be held
-    SharedBufferServer*     lcblk;
+            Layer(SurfaceFlinger* flinger, DisplayID display,
+                    const sp<Client>& client);
 
-                 Layer(SurfaceFlinger* flinger, DisplayID display,
-                         const sp<Client>& client, int32_t i);
+    virtual ~Layer();
 
-        virtual ~Layer();
+    virtual const char* getTypeId() const { return "Layer"; }
 
+    // the this layer's size and format
     status_t setBuffers(uint32_t w, uint32_t h, 
             PixelFormat format, uint32_t flags=0);
 
+    // associate a UserClient to this Layer
+    status_t setToken(const sp<UserClient>& uc, SharedClient* sc, int32_t idx);
+    int32_t getToken() const;
+
+    // Set this Layer's buffers size
     void setBufferSize(uint32_t w, uint32_t h);
     bool isFixedSize() const;
 
+    // LayerBase interface
     virtual void onDraw(const Region& clip) const;
     virtual uint32_t doTransaction(uint32_t transactionFlags);
     virtual void lockPageFlip(bool& recomputeVisibleRegions);
@@ -72,32 +78,29 @@
     virtual sp<Surface> createSurface() const;
     virtual status_t ditch();
     virtual void onRemoved();
-    
-    // only for debugging
-    inline sp<GraphicBuffer> getBuffer(int i) const { return mBufferManager.getBuffer(i); }
-    // only for debugging
-    inline const sp<FreezeLock>&  getFreezeLock() const { return mFreezeLock; }
-    // only for debugging
-    inline PixelFormat pixelFormat() const { return mFormat; }
 
-    virtual const char* getTypeId() const { return "Layer"; }
+    // only for debugging
+    inline sp<GraphicBuffer> getBuffer(int i) const {
+        return mBufferManager.getBuffer(i); }
+    // only for debugging
+    inline const sp<FreezeLock>&  getFreezeLock() const {
+        return mFreezeLock; }
 
 protected:
     virtual void dump(String8& result, char* scratch, size_t size) const;
 
 private:
     void reloadTexture(const Region& dirty);
-
     uint32_t getEffectiveUsage(uint32_t usage) const;
-
     sp<GraphicBuffer> requestBuffer(int bufferIdx,
             uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
     status_t setBufferCount(int bufferCount);
 
+    // -----------------------------------------------------------------------
+
     class SurfaceLayer : public LayerBaseClient::Surface {
     public:
-        SurfaceLayer(const sp<SurfaceFlinger>& flinger,
-                SurfaceID id, const sp<Layer>& owner);
+        SurfaceLayer(const sp<SurfaceFlinger>& flinger, const sp<Layer>& owner);
         ~SurfaceLayer();
     private:
         virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
@@ -108,87 +111,120 @@
         }
     };
     friend class SurfaceLayer;
-    
-    sp<Surface>             mSurface;
 
-            bool            mSecure;
-            int32_t         mFrontBufferIndex;
-            bool            mNeedsBlending;
-            bool            mNeedsDithering;
-            Region          mPostedDirtyRegion;
-            sp<FreezeLock>  mFreezeLock;
-            PixelFormat     mFormat;
+    // -----------------------------------------------------------------------
 
-            class BufferManager {
-                static const size_t NUM_BUFFERS = 2;
-                struct BufferData {
-                    sp<GraphicBuffer>   buffer;
-                    Image               texture;
-                };
-                // this lock protect mBufferData[].buffer but since there
-                // is very little contention, we have only one like for
-                // the whole array, we also use it to protect mNumBuffers.
-                mutable Mutex mLock;
-                BufferData          mBufferData[SharedBufferStack::NUM_BUFFER_MAX];
-                size_t              mNumBuffers;
-                Texture             mFailoverTexture;
-                TextureManager&     mTextureManager;
-                ssize_t             mActiveBuffer;
-                bool                mFailover;
-                static status_t destroyTexture(Image* tex, EGLDisplay dpy);
+    class ClientRef {
+        ClientRef(const ClientRef& rhs);
+        ClientRef& operator = (const ClientRef& rhs);
+        mutable Mutex mLock;
+        // binder thread, page-flip thread
+        SharedBufferServer* lcblk;
+        wp<UserClient> mUserClient;
+        int32_t mToken;
+    public:
+        ClientRef();
+        ~ClientRef();
+        int32_t getToken() const;
+        status_t setToken(const sp<UserClient>& uc,
+                SharedBufferServer* sharedClient, int32_t token);
+        sp<UserClient> getUserClientUnsafe() const;
+        class Access {
+            Access(const Access& rhs);
+            Access& operator = (const Access& rhs);
+            sp<UserClient> mUserClientStrongRef;
+            SharedBufferServer* lcblk;
+        public:
+            Access(const ClientRef& ref);
+            inline SharedBufferServer* get() const { return lcblk; }
+        };
+        friend class Access;
+    };
 
-            public:
-                static size_t getDefaultBufferCount() { return NUM_BUFFERS; }
-                BufferManager(TextureManager& tm);
-                ~BufferManager();
+    // -----------------------------------------------------------------------
 
-                // detach/attach buffer from/to given index
-                sp<GraphicBuffer> detachBuffer(size_t index);
-                status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer);
+    class BufferManager {
+        static const size_t NUM_BUFFERS = 2;
+        struct BufferData {
+            sp<GraphicBuffer>   buffer;
+            Image               texture;
+        };
+        // this lock protect mBufferData[].buffer but since there
+        // is very little contention, we have only one like for
+        // the whole array, we also use it to protect mNumBuffers.
+        mutable Mutex mLock;
+        BufferData          mBufferData[SharedBufferStack::NUM_BUFFER_MAX];
+        size_t              mNumBuffers;
+        Texture             mFailoverTexture;
+        TextureManager&     mTextureManager;
+        ssize_t             mActiveBuffer;
+        bool                mFailover;
+        static status_t destroyTexture(Image* tex, EGLDisplay dpy);
 
-                // resize the number of active buffers
-                status_t resize(size_t size);
+    public:
+        static size_t getDefaultBufferCount() { return NUM_BUFFERS; }
+        BufferManager(TextureManager& tm);
+        ~BufferManager();
 
-                // ----------------------------------------------
-                // must be called from GL thread
+        // detach/attach buffer from/to given index
+        sp<GraphicBuffer> detachBuffer(size_t index);
+        status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer);
+        // resize the number of active buffers
+        status_t resize(size_t size);
 
-                // set/get active buffer index
-                status_t setActiveBufferIndex(size_t index);
-                size_t getActiveBufferIndex() const;
+        // ----------------------------------------------
+        // must be called from GL thread
 
-                // return the active buffer
-                sp<GraphicBuffer> getActiveBuffer() const;
+        // set/get active buffer index
+        status_t setActiveBufferIndex(size_t index);
+        size_t getActiveBufferIndex() const;
+        // return the active buffer
+        sp<GraphicBuffer> getActiveBuffer() const;
+        // return the active texture (or fail-over)
+        Texture getActiveTexture() const;
+        // frees resources associated with all buffers
+        status_t destroy(EGLDisplay dpy);
+        // load bitmap data into the active buffer
+        status_t loadTexture(const Region& dirty, const GGLSurface& t);
+        // make active buffer an EGLImage if needed
+        status_t initEglImage(EGLDisplay dpy,
+                const sp<GraphicBuffer>& buffer);
 
-                // return the active texture (or fail-over)
-                Texture getActiveTexture() const;
+        // ----------------------------------------------
+        // only for debugging
+        sp<GraphicBuffer> getBuffer(size_t index) const;
+    };
 
-                // frees resources associated with all buffers
-                status_t destroy(EGLDisplay dpy);
+    // -----------------------------------------------------------------------
 
-                // load bitmap data into the active buffer
-                status_t loadTexture(const Region& dirty, const GGLSurface& t);
+    // thread-safe
+    ClientRef mUserClientRef;
 
-                // make active buffer an EGLImage if needed
-                status_t initEglImage(EGLDisplay dpy,
-                        const sp<GraphicBuffer>& buffer);
+    // constants
+    sp<Surface> mSurface;
+    PixelFormat mFormat;
+    bool mNeedsBlending;
+    bool mNeedsDithering;
 
-                // ----------------------------------------------
-                // only for debugging
-                sp<GraphicBuffer> getBuffer(size_t index) const;
-            };
+    // page-flip thread (currently main thread)
+    bool mSecure;
+    Region mPostedDirtyRegion;
 
-            TextureManager mTextureManager;
-            BufferManager mBufferManager;
+    // page-flip thread and transaction thread (currently main thread)
+    sp<FreezeLock>  mFreezeLock;
 
-            // this lock protects mWidth and mHeight which are accessed from
-            // the main thread and requestBuffer's binder transaction thread.
-            mutable Mutex mLock;
-            uint32_t    mWidth;
-            uint32_t    mHeight;
-            uint32_t    mReqWidth;
-            uint32_t    mReqHeight;
-            uint32_t    mReqFormat;
-            bool        mFixedSize;
+    // see threading usage in declaration
+    TextureManager mTextureManager;
+    BufferManager mBufferManager;
+
+    // binder thread, transaction thread
+    mutable Mutex mLock;
+    uint32_t mWidth;
+    uint32_t mHeight;
+    uint32_t mReqWidth;
+    uint32_t mReqHeight;
+    uint32_t mReqFormat;
+    bool mFixedSize;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 7ab74b4..1f66fd0 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -151,7 +151,6 @@
     return true;
 }
 bool LayerBase::setMatrix(const layer_state_t::matrix22_t& matrix) {
-    // TODO: check the matrix has changed
     mCurrentState.sequence++;
     mCurrentState.transform.set(
             matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy);
@@ -159,7 +158,6 @@
     return true;
 }
 bool LayerBase::setTransparentRegionHint(const Region& transparent) {
-    // TODO: check the region has changed
     mCurrentState.sequence++;
     mCurrentState.transparentRegion = transparent;
     requestTransaction();
@@ -488,37 +486,20 @@
 int32_t LayerBaseClient::sIdentity = 1;
 
 LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
-        const sp<Client>& client, int32_t i)
-    : LayerBase(flinger, display), client(client), mIndex(i),
+        const sp<Client>& client)
+    : LayerBase(flinger, display), mClientRef(client),
       mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
 {
 }
 
-void LayerBaseClient::onFirstRef()
-{    
-    sp<Client> client(this->client.promote());
-    if (client != 0) {
-        client->bindLayer(this, mIndex);
-    }
-}
-
 LayerBaseClient::~LayerBaseClient()
 {
-    sp<Client> client(this->client.promote());
-    if (client != 0) {
-        client->free(mIndex);
+    sp<Client> c(mClientRef.promote());
+    if (c != 0) {
+        c->detachLayer(this);
     }
 }
 
-ssize_t LayerBaseClient::serverIndex() const
-{
-    sp<Client> client(this->client.promote());
-    if (client != 0) {
-        return (client->cid<<16)|mIndex;
-    }
-    return ssize_t(0xFFFF0000 | mIndex);
-}
-
 sp<LayerBaseClient::Surface> LayerBaseClient::getSurface()
 {
     sp<Surface> s;
@@ -533,7 +514,7 @@
 
 sp<LayerBaseClient::Surface> LayerBaseClient::createSurface() const
 {
-    return new Surface(mFlinger, clientIndex(), mIdentity,
+    return new Surface(mFlinger, mIdentity,
             const_cast<LayerBaseClient *>(this));
 }
 
@@ -541,13 +522,12 @@
 {
     LayerBase::dump(result, buffer, SIZE);
 
-    sp<Client> client(this->client.promote());
+    sp<Client> client(mClientRef.promote());
     snprintf(buffer, SIZE,
             "      name=%s\n"
-            "      id=0x%08x, client=0x%08x, identity=%u\n",
+            "      client=%p, identity=%u\n",
             getName().string(),
-            clientIndex(), client.get() ? client->cid : 0,
-            getIdentity());
+            client.get(), getIdentity());
 
     result.append(buffer);
 }
@@ -556,9 +536,9 @@
 
 LayerBaseClient::Surface::Surface(
         const sp<SurfaceFlinger>& flinger,
-        SurfaceID id, int identity, 
+        int identity,
         const sp<LayerBaseClient>& owner) 
-    : mFlinger(flinger), mToken(id), mIdentity(identity), mOwner(owner)
+    : mFlinger(flinger), mIdentity(identity), mOwner(owner)
 {
 }
 
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 2e2f2df..1a07f32 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -45,6 +45,7 @@
 class Client;
 class GraphicBuffer;
 class GraphicPlane;
+class LayerBaseClient;
 class SurfaceFlinger;
 class Texture;
 
@@ -100,8 +101,9 @@
 
             void invalidate();
 
+    virtual sp<LayerBaseClient> getLayerBaseClient() const { return 0; }
+
     virtual const char* getTypeId() const { return "LayerBase"; }
-    virtual ssize_t serverIndex() const { return -1; }
 
     /**
      * draw - performs some global clipping optimizations
@@ -269,30 +271,24 @@
 public:
     class Surface;
 
-    LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, 
-            const sp<Client>& client, int32_t i);
+            LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
+                        const sp<Client>& client);
     virtual ~LayerBaseClient();
-    virtual void onFirstRef();
 
-    const wp<Client>    client;
-
-    inline  uint32_t    getIdentity() const { return mIdentity; }
-    inline  int32_t     clientIndex() const { return mIndex; }
-   
             sp<Surface> getSurface();
     virtual sp<Surface> createSurface() const;
-    virtual ssize_t     serverIndex() const;
+    virtual sp<LayerBaseClient> getLayerBaseClient() const {
+        return const_cast<LayerBaseClient*>(this); }
     virtual const char* getTypeId() const { return "LayerBaseClient"; }
 
-    class Surface : public BnSurface 
-    {
+    uint32_t getIdentity() const { return mIdentity; }
+
+    class Surface : public BnSurface  {
     public:
-        int32_t getToken() const { return mToken; }
         int32_t getIdentity() const { return mIdentity; }
         
     protected:
-        Surface(const sp<SurfaceFlinger>& flinger, 
-                SurfaceID id, int identity, 
+        Surface(const sp<SurfaceFlinger>& flinger, int identity,
                 const sp<LayerBaseClient>& owner);
         virtual ~Surface();
         virtual status_t onTransact(uint32_t code, const Parcel& data,
@@ -313,7 +309,6 @@
     protected:
         friend class LayerBaseClient;
         sp<SurfaceFlinger>  mFlinger;
-        int32_t             mToken;
         int32_t             mIdentity;
         wp<LayerBaseClient> mOwner;
     };
@@ -324,12 +319,12 @@
     virtual void dump(String8& result, char* scratch, size_t size) const;
 
 private:
-    int32_t         mIndex;
-    mutable     Mutex           mLock;
-    mutable     wp<Surface>     mClientSurface;
+    mutable Mutex mLock;
+    mutable wp<Surface> mClientSurface;
+    const wp<Client> mClientRef;
     // only read
-    const       uint32_t        mIdentity;
-    static      int32_t         sIdentity;
+    const uint32_t mIdentity;
+    static int32_t sIdentity;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index 09c90e8..4c8bae8 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -34,8 +34,8 @@
 // ---------------------------------------------------------------------------
 
 LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
-        const sp<Client>& client, int32_t i)
-    : LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
+        const sp<Client>& client)
+    : LayerBaseClient(flinger, display, client), mCacheDirty(true),
           mRefreshCache(true), mCacheAge(0), mTextureName(-1U),
           mWidthScale(1.0f), mHeightScale(1.0f),
           mBlurFormat(GGL_PIXEL_FORMAT_RGB_565)
diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h
index 380f587..4c9ec64 100644
--- a/libs/surfaceflinger/LayerBlur.h
+++ b/libs/surfaceflinger/LayerBlur.h
@@ -32,7 +32,7 @@
 {
 public:    
                 LayerBlur(SurfaceFlinger* flinger, DisplayID display,
-                        const sp<Client>& client, int32_t i);
+                        const sp<Client>& client);
         virtual ~LayerBlur();
 
     virtual void onDraw(const Region& clip) const;
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 8a582da..732a4ec 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -44,8 +44,8 @@
 // ---------------------------------------------------------------------------
 
 LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
-        const sp<Client>& client, int32_t i)
-    : LayerBaseClient(flinger, display, client, i),
+        const sp<Client>& client)
+    : LayerBaseClient(flinger, display, client),
       mNeedsBlending(false), mBlitEngine(0)
 {
 }
@@ -60,8 +60,7 @@
 void LayerBuffer::onFirstRef()
 {
     LayerBaseClient::onFirstRef();
-    mSurface = new SurfaceLayerBuffer(mFlinger, clientIndex(),
-            const_cast<LayerBuffer *>(this));
+    mSurface = new SurfaceLayerBuffer(mFlinger, this);
 
     hw_module_t const* module = (hw_module_t const*)sGrallocModule;
     if (!module) {
@@ -204,9 +203,9 @@
 // LayerBuffer::SurfaceLayerBuffer
 // ============================================================================
 
-LayerBuffer::SurfaceLayerBuffer::SurfaceLayerBuffer(const sp<SurfaceFlinger>& flinger,
-        SurfaceID id, const sp<LayerBuffer>& owner)
-    : LayerBaseClient::Surface(flinger, id, owner->getIdentity(), owner)
+LayerBuffer::SurfaceLayerBuffer::SurfaceLayerBuffer(
+        const sp<SurfaceFlinger>& flinger, const sp<LayerBuffer>& owner)
+    : LayerBaseClient::Surface(flinger, owner->getIdentity(), owner)
 {
 }
 
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index d38dde2..413b8a4 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -53,7 +53,7 @@
 
 public:
             LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
-                    const sp<Client>& client, int32_t i);
+                    const sp<Client>& client);
         virtual ~LayerBuffer();
 
     virtual void onFirstRef();
@@ -189,7 +189,7 @@
     {
     public:
         SurfaceLayerBuffer(const sp<SurfaceFlinger>& flinger,
-                        SurfaceID id, const sp<LayerBuffer>& owner);
+                        const sp<LayerBuffer>& owner);
         virtual ~SurfaceLayerBuffer();
 
         virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
index 568fedb..d528d2f 100644
--- a/libs/surfaceflinger/LayerDim.cpp
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -39,8 +39,8 @@
 // ---------------------------------------------------------------------------
 
 LayerDim::LayerDim(SurfaceFlinger* flinger, DisplayID display,
-        const sp<Client>& client, int32_t i)
-    : LayerBaseClient(flinger, display, client, i)
+        const sp<Client>& client)
+    : LayerBaseClient(flinger, display, client)
 {
 }
 
diff --git a/libs/surfaceflinger/LayerDim.h b/libs/surfaceflinger/LayerDim.h
index 19a9990..f032314 100644
--- a/libs/surfaceflinger/LayerDim.h
+++ b/libs/surfaceflinger/LayerDim.h
@@ -38,7 +38,7 @@
     static int32_t sHeight;
 public:    
                 LayerDim(SurfaceFlinger* flinger, DisplayID display,
-                        const sp<Client>& client, int32_t i);
+                        const sp<Client>& client);
         virtual ~LayerDim();
 
     virtual void onDraw(const Region& clip) const;
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index fff0853..0f73774 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -227,54 +227,27 @@
 
 sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
 {
-    Mutex::Autolock _l(mStateLock);
-    uint32_t token = mTokens.acquire();
-
-    sp<Client> client = new Client(token, this);
-    if (client->ctrlblk == 0) {
-        mTokens.release(token);
-        return 0;
+    sp<ISurfaceComposerClient> bclient;
+    sp<Client> client(new Client(this));
+    status_t err = client->initCheck();
+    if (err == NO_ERROR) {
+        bclient = client;
     }
-    status_t err = mClientsMap.add(token, client);
-    if (err < 0) {
-        mTokens.release(token);
-        return 0;
-    }
-    sp<BClient> bclient =
-        new BClient(this, token, client->getControlBlockMemory());
     return bclient;
 }
 
-void SurfaceFlinger::destroyConnection(ClientID cid)
+sp<ISurfaceComposerClient> SurfaceFlinger::createClientConnection()
 {
-    Mutex::Autolock _l(mStateLock);
-    sp<Client> client = mClientsMap.valueFor(cid);
-    if (client != 0) {
-        // free all the layers this client owns
-        Vector< wp<LayerBaseClient> > layers(client->getLayers());
-        const size_t count = layers.size();
-        for (size_t i=0 ; i<count ; i++) {
-            sp<LayerBaseClient> layer(layers[i].promote());
-            if (layer != 0) {
-                purgatorizeLayer_l(layer);
-            }
-        }
-
-        // the resources associated with this client will be freed
-        // during the next transaction, after these surfaces have been
-        // properly removed from the screen
-
-        // remove this client from our ClientID->Client mapping.
-        mClientsMap.removeItem(cid);
-
-        // and add it to the list of disconnected clients
-        mDisconnectedClients.add(client);
-
-        // request a transaction
-        setTransactionFlags(eTransactionNeeded);
+    sp<ISurfaceComposerClient> bclient;
+    sp<UserClient> client(new UserClient(this));
+    status_t err = client->initCheck();
+    if (err == NO_ERROR) {
+        bclient = client;
     }
+    return bclient;
 }
 
+
 const GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) const
 {
     LOGE_IF(uint32_t(dpy) >= DISPLAY_COUNT, "Invalid DisplayID %d", dpy);
@@ -665,10 +638,6 @@
                 }
             }
         }
-
-        // get rid of all resources we don't need anymore
-        // (layers and clients)
-        free_resources_l();
     }
 
     commitTransaction();
@@ -815,7 +784,8 @@
 void SurfaceFlinger::handlePageFlip()
 {
     bool visibleRegions = mVisibleRegionsDirty;
-    LayerVector& currentLayers = const_cast<LayerVector&>(mDrawingState.layersSortedByZ);
+    LayerVector& currentLayers = const_cast<LayerVector&>(
+            mDrawingState.layersSortedByZ);
     visibleRegions |= lockPageFlip(currentLayers);
 
         const DisplayHardware& hw = graphicPlane(0).displayHardware();
@@ -837,7 +807,7 @@
     size_t count = currentLayers.size();
     sp<LayerBase> const* layers = currentLayers.array();
     for (size_t i=0 ; i<count ; i++) {
-        const sp<LayerBase>& layer = layers[i];
+        const sp<LayerBase>& layer(layers[i]);
         layer->lockPageFlip(recomputeVisibleRegions);
     }
     return recomputeVisibleRegions;
@@ -850,7 +820,7 @@
     size_t count = currentLayers.size();
     sp<LayerBase> const* layers = currentLayers.array();
     for (size_t i=0 ; i<count ; i++) {
-        const sp<LayerBase>& layer = layers[i];
+        const sp<LayerBase>& layer(layers[i]);
         layer->unlockPageFlip(planeTransform, mDirtyRegion);
     }
 }
@@ -882,7 +852,7 @@
         // takes a rectangle, we must make sure to update that whole
         // rectangle in that case
         if (flags & DisplayHardware::SWAP_RECTANGLE) {
-            // FIXME: we really should be able to pass a region to
+            // TODO: we really should be able to pass a region to
             // SWAP_RECTANGLE so that we don't have to redraw all this.
             mDirtyRegion.set(mInvalidRegion.bounds());
         } else {
@@ -1071,6 +1041,27 @@
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer)
+{
+    ssize_t i = mCurrentState.layersSortedByZ.add(
+                layer, &LayerBase::compareCurrentStateZ);
+    return (i < 0) ? status_t(i) : status_t(NO_ERROR);
+}
+
+ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
+        const sp<LayerBaseClient>& lbc)
+{
+    Mutex::Autolock _l(mStateLock);
+
+    // attach this layer to the client
+    ssize_t name = client->attachLayer(lbc);
+
+    // add this layer to the current state list
+    addLayer_l(lbc);
+
+    return name;
+}
+
 status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer)
 {
     Mutex::Autolock _l(mStateLock);
@@ -1080,35 +1071,15 @@
     return err;
 }
 
-status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer)
-{
-    layer->forceVisibilityTransaction();
-    setTransactionFlags(eTraversalNeeded);
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer)
-{
-    ssize_t i = mCurrentState.layersSortedByZ.add(
-                layer, &LayerBase::compareCurrentStateZ);
-    return (i < 0) ? status_t(i) : status_t(NO_ERROR);
-}
-
-status_t SurfaceFlinger::addClientLayer_l(const sp<LayerBaseClient>& lbc)
-{
-    ssize_t serverIndex = lbc->serverIndex();
-    return mLayerMap.add(serverIndex, lbc);
-}
-
 status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase)
 {
+    sp<LayerBaseClient> lbc(layerBase->getLayerBaseClient());
+    if (lbc != 0) {
+        mLayerMap.removeItem( lbc->getSurface()->asBinder() );
+    }
     ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase);
     if (index >= 0) {
         mLayersRemoved = true;
-        ssize_t serverIndex = layerBase->serverIndex();
-        if (serverIndex >= 0) {
-            mLayerMap.removeItem(serverIndex);
-        }
         return NO_ERROR;
     }
     return status_t(index);
@@ -1123,22 +1094,16 @@
 
     // it's possible that we don't find a layer, because it might
     // have been destroyed already -- this is not technically an error
-    // from the user because there is a race between BClient::destroySurface(),
-    // ~BClient() and ~ISurface().
+    // from the user because there is a race between Client::destroySurface(),
+    // ~Client() and ~ISurface().
     return (err == NAME_NOT_FOUND) ? status_t(NO_ERROR) : err;
 }
 
-
-void SurfaceFlinger::free_resources_l()
+status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer)
 {
-    // free resources associated with disconnected clients
-    Vector< sp<Client> >& disconnectedClients(mDisconnectedClients);
-    const size_t count = disconnectedClients.size();
-    for (size_t i=0 ; i<count ; i++) {
-        sp<Client> client = disconnectedClients[i];
-        mTokens.release(client->cid);
-    }
-    disconnectedClients.clear();
+    layer->forceVisibilityTransaction();
+    setTransactionFlags(eTraversalNeeded);
+    return NO_ERROR;
 }
 
 uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
@@ -1229,7 +1194,7 @@
     return orientation;
 }
 
-sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,
+sp<ISurface> SurfaceFlinger::createSurface(const sp<Client>& client, int pid,
         const String8& name, ISurfaceComposerClient::surface_data_t* params,
         DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
         uint32_t flags)
@@ -1243,57 +1208,52 @@
         return surfaceHandle;
     }
     
-    Mutex::Autolock _l(mStateLock);
-    sp<Client> client = mClientsMap.valueFor(clientId);
-    if (UNLIKELY(client == 0)) {
-        LOGE("createSurface() failed, client not found (id=%d)", clientId);
-        return surfaceHandle;
-    }
-
     //LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
-    int32_t id = client->generateId(pid);
-    if (uint32_t(id) >= SharedBufferStack::NUM_LAYERS_MAX) {
-        LOGE("createSurface() failed, generateId = %d", id);
-        return surfaceHandle;
-    }
-
+    sp<Layer> normalLayer;
     switch (flags & eFXSurfaceMask) {
         case eFXSurfaceNormal:
             if (UNLIKELY(flags & ePushBuffers)) {
-                layer = createPushBuffersSurfaceLocked(client, d, id,
-                        w, h, flags);
+                layer = createPushBuffersSurface(client, d, w, h, flags);
             } else {
-                layer = createNormalSurfaceLocked(client, d, id,
-                        w, h, flags, format);
+                normalLayer = createNormalSurface(client, d, w, h, flags, format);
+                layer = normalLayer;
             }
             break;
         case eFXSurfaceBlur:
-            layer = createBlurSurfaceLocked(client, d, id, w, h, flags);
+            layer = createBlurSurface(client, d, w, h, flags);
             break;
         case eFXSurfaceDim:
-            layer = createDimSurfaceLocked(client, d, id, w, h, flags);
+            layer = createDimSurface(client, d, w, h, flags);
             break;
     }
 
     if (layer != 0) {
+        layer->initStates(w, h, flags);
         layer->setName(name);
-        setTransactionFlags(eTransactionNeeded);
+        ssize_t token = addClientLayer(client, layer);
+
         surfaceHandle = layer->getSurface();
         if (surfaceHandle != 0) { 
-            params->token = surfaceHandle->getToken();
+            params->token = token;
             params->identity = surfaceHandle->getIdentity();
             params->width = w;
             params->height = h;
             params->format = format;
+            if (normalLayer != 0) {
+                Mutex::Autolock _l(mStateLock);
+                mLayerMap.add(surfaceHandle->asBinder(), normalLayer);
+            }
         }
+
+        setTransactionFlags(eTransactionNeeded);
     }
 
     return surfaceHandle;
 }
 
-sp<LayerBaseClient> SurfaceFlinger::createNormalSurfaceLocked(
+sp<Layer> SurfaceFlinger::createNormalSurface(
         const sp<Client>& client, DisplayID display,
-        int32_t id, uint32_t w, uint32_t h, uint32_t flags,
+        uint32_t w, uint32_t h, uint32_t flags,
         PixelFormat& format)
 {
     // initialize the surfaces
@@ -1307,53 +1267,43 @@
         break;
     }
 
-    sp<Layer> layer = new Layer(this, display, client, id);
+    sp<Layer> layer = new Layer(this, display, client);
     status_t err = layer->setBuffers(w, h, format, flags);
-    if (LIKELY(err == NO_ERROR)) {
-        layer->initStates(w, h, flags);
-        addLayer_l(layer);
-        addClientLayer_l(layer);
-    } else {
+    if (LIKELY(err != NO_ERROR)) {
         LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err));
         layer.clear();
     }
     return layer;
 }
 
-sp<LayerBaseClient> SurfaceFlinger::createBlurSurfaceLocked(
+sp<LayerBlur> SurfaceFlinger::createBlurSurface(
         const sp<Client>& client, DisplayID display,
-        int32_t id, uint32_t w, uint32_t h, uint32_t flags)
+        uint32_t w, uint32_t h, uint32_t flags)
 {
-    sp<LayerBlur> layer = new LayerBlur(this, display, client, id);
+    sp<LayerBlur> layer = new LayerBlur(this, display, client);
     layer->initStates(w, h, flags);
-    addLayer_l(layer);
-    addClientLayer_l(layer);
     return layer;
 }
 
-sp<LayerBaseClient> SurfaceFlinger::createDimSurfaceLocked(
+sp<LayerDim> SurfaceFlinger::createDimSurface(
         const sp<Client>& client, DisplayID display,
-        int32_t id, uint32_t w, uint32_t h, uint32_t flags)
+        uint32_t w, uint32_t h, uint32_t flags)
 {
-    sp<LayerDim> layer = new LayerDim(this, display, client, id);
+    sp<LayerDim> layer = new LayerDim(this, display, client);
     layer->initStates(w, h, flags);
-    addLayer_l(layer);
-    addClientLayer_l(layer);
     return layer;
 }
 
-sp<LayerBaseClient> SurfaceFlinger::createPushBuffersSurfaceLocked(
+sp<LayerBuffer> SurfaceFlinger::createPushBuffersSurface(
         const sp<Client>& client, DisplayID display,
-        int32_t id, uint32_t w, uint32_t h, uint32_t flags)
+        uint32_t w, uint32_t h, uint32_t flags)
 {
-    sp<LayerBuffer> layer = new LayerBuffer(this, display, client, id);
+    sp<LayerBuffer> layer = new LayerBuffer(this, display, client);
     layer->initStates(w, h, flags);
-    addLayer_l(layer);
-    addClientLayer_l(layer);
     return layer;
 }
 
-status_t SurfaceFlinger::removeSurface(SurfaceID index)
+status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid)
 {
     /*
      * called by the window manager, when a surface should be marked for
@@ -1366,7 +1316,7 @@
 
     status_t err = NAME_NOT_FOUND;
     Mutex::Autolock _l(mStateLock);
-    sp<LayerBaseClient> layer = getLayerUser_l(index);
+    sp<LayerBaseClient> layer = client->getLayerUser(sid);
     if (layer != 0) {
         err = purgatorizeLayer_l(layer);
         if (err == NO_ERROR) {
@@ -1411,16 +1361,15 @@
 }
 
 status_t SurfaceFlinger::setClientState(
-        ClientID cid,
+        const sp<Client>& client,
         int32_t count,
         const layer_state_t* states)
 {
     Mutex::Autolock _l(mStateLock);
     uint32_t flags = 0;
-    cid <<= 16;
     for (int i=0 ; i<count ; i++) {
-        const layer_state_t& s = states[i];
-        sp<LayerBaseClient> layer(getLayerUser_l(s.surface | cid));
+        const layer_state_t& s(states[i]);
+        sp<LayerBaseClient> layer(client->getLayerUser(s.surface));
         if (layer != 0) {
             const uint32_t what = s.what;
             if (what & ePositionChanged) {
@@ -1466,12 +1415,6 @@
     return NO_ERROR;
 }
 
-sp<LayerBaseClient> SurfaceFlinger::getLayerUser_l(SurfaceID s) const
-{
-    sp<LayerBaseClient> layer = mLayerMap.valueFor(s);
-    return layer;
-}
-
 void SurfaceFlinger::screenReleased(int dpy)
 {
     // this may be called by a signal handler, we can't do too much in here
@@ -1557,8 +1500,6 @@
             result.append(buffer);
         }
 
-        snprintf(buffer, SIZE, "  client count: %d\n", mClientsMap.size());
-        result.append(buffer);
         const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
         alloc.dump(result);
 
@@ -1651,12 +1592,91 @@
 }
 
 // ---------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
 
-Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger)
-    : ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)
+sp<Layer> SurfaceFlinger::getLayer(const sp<ISurface>& sur) const
+{
+    sp<Layer> result;
+    Mutex::Autolock _l(mStateLock);
+    result = mLayerMap.valueFor( sur->asBinder() ).promote();
+    return result;
+}
+
+// ---------------------------------------------------------------------------
+
+Client::Client(const sp<SurfaceFlinger>& flinger)
+    : mFlinger(flinger), mNameGenerator(1)
+{
+}
+
+Client::~Client()
+{
+    const size_t count = mLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        sp<LayerBaseClient> layer(mLayers.valueAt(i).promote());
+        if (layer != 0) {
+            mFlinger->removeLayer(layer);
+        }
+    }
+}
+
+status_t Client::initCheck() const {
+    return NO_ERROR;
+}
+
+ssize_t Client::attachLayer(const sp<LayerBaseClient>& layer)
+{
+    int32_t name = android_atomic_inc(&mNameGenerator);
+    mLayers.add(name, layer);
+    return name;
+}
+
+void Client::detachLayer(const LayerBaseClient* layer)
+{
+    // we do a linear search here, because this doesn't happen often
+    const size_t count = mLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        if (mLayers.valueAt(i) == layer) {
+            mLayers.removeItemsAt(i, 1);
+            break;
+        }
+    }
+}
+sp<LayerBaseClient> Client::getLayerUser(int32_t i) const {
+    sp<LayerBaseClient> lbc;
+    const wp<LayerBaseClient>& layer(mLayers.valueFor(i));
+    if (layer != 0) {
+        lbc = layer.promote();
+        LOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i));
+    }
+    return lbc;
+}
+
+sp<IMemoryHeap> Client::getControlBlock() const {
+    return 0;
+}
+ssize_t Client::getTokenForSurface(const sp<ISurface>& sur) const {
+    return -1;
+}
+sp<ISurface> Client::createSurface(
+        ISurfaceComposerClient::surface_data_t* params, int pid,
+        const String8& name,
+        DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
+        uint32_t flags)
+{
+    return mFlinger->createSurface(this, pid, name, params,
+            display, w, h, format, flags);
+}
+status_t Client::destroySurface(SurfaceID sid) {
+    return mFlinger->removeSurface(this, sid);
+}
+status_t Client::setState(int32_t count, const layer_state_t* states) {
+    return mFlinger->setClientState(this, count, states);
+}
+
+// ---------------------------------------------------------------------------
+
+UserClient::UserClient(const sp<SurfaceFlinger>& flinger)
+    : ctrlblk(0), mBitmap(0), mFlinger(flinger)
 {
     const int pgsize = getpagesize();
     const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1));
@@ -1670,94 +1690,81 @@
     }
 }
 
-Client::~Client() {
+UserClient::~UserClient()
+{
     if (ctrlblk) {
         ctrlblk->~SharedClient();  // destroy our shared-structure.
     }
+
+    /*
+     * When a UserClient dies, it's unclear what to do exactly.
+     * We could go ahead and destroy all surfaces linked to that client
+     * however, it wouldn't be fair to the main Client
+     * (usually the the window-manager), which might want to re-target
+     * the layer to another UserClient.
+     * I think the best is to do nothing, or not much; in most cases the
+     * WM itself will go ahead and clean things up when it detects a client of
+     * his has died.
+     * The remaining question is what to display? currently we keep
+     * just keep the current buffer.
+     */
 }
 
-int32_t Client::generateId(int pid)
-{
-    const uint32_t i = clz( ~mBitmap );
-    if (i >= SharedBufferStack::NUM_LAYERS_MAX) {
-        return NO_MEMORY;
-    }
-    mPid = pid;
-    mInUse.add(uint8_t(i));
-    mBitmap |= 1<<(31-i);
-    return i;
+status_t UserClient::initCheck() const {
+    return ctrlblk == 0 ? NO_INIT : NO_ERROR;
 }
 
-status_t Client::bindLayer(const sp<LayerBaseClient>& layer, int32_t id)
+void UserClient::detachLayer(const Layer* layer)
 {
-    ssize_t idx = mInUse.indexOf(id);
-    if (idx < 0)
-        return NAME_NOT_FOUND;
-    return mLayers.insertAt(layer, idx);
-}
-
-void Client::free(int32_t id)
-{
-    ssize_t idx = mInUse.remove(uint8_t(id));
-    if (idx >= 0) {
-        mBitmap &= ~(1<<(31-id));
-        mLayers.removeItemsAt(idx);
+    int32_t name = layer->getToken();
+    if (name >= 0) {
+        android_atomic_and(~(1LU<<name), &mBitmap);
     }
 }
 
-bool Client::isValid(int32_t i) const {
-    return (uint32_t(i)<SharedBufferStack::NUM_LAYERS_MAX) &&
-            (mBitmap & (1<<(31-i)));
+sp<IMemoryHeap> UserClient::getControlBlock() const {
+    return mCblkHeap;
 }
 
-sp<LayerBaseClient> Client::getLayerUser(int32_t i) const {
-    sp<LayerBaseClient> lbc;
-    ssize_t idx = mInUse.indexOf(uint8_t(i));
-    if (idx >= 0) {
-        lbc = mLayers[idx].promote();
-        LOGE_IF(lbc==0, "getLayerUser(i=%d), idx=%d is dead", int(i), int(idx));
-    }
-    return lbc;
-}
-
-// ---------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-BClient::BClient(SurfaceFlinger *flinger, ClientID cid, const sp<IMemoryHeap>& cblk)
-    : mId(cid), mFlinger(flinger), mCblk(cblk)
+ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const
 {
+    int32_t name = NAME_NOT_FOUND;
+    sp<Layer> layer(mFlinger->getLayer(sur));
+    if (layer == 0) return name;
+
+    // this layer already has a token, just return it
+    // FIXME: we should check that this token is for the same client
+    name = layer->getToken();
+    if (name >= 0) return name;
+
+    name = 0;
+    do {
+        int32_t mask = 1LU<<name;
+        if ((android_atomic_or(mask, &mBitmap) & mask) == 0) {
+            // we found and locked that name
+            layer->setToken(const_cast<UserClient*>(this), ctrlblk, name);
+            break;
+        }
+        if (++name > 31)
+            name = NO_MEMORY;
+    } while(name >= 0);
+
+    //LOGD("getTokenForSurface(%p) => %d", sur->asBinder().get(), name);
+    return name;
 }
 
-BClient::~BClient() {
-    // destroy all resources attached to this client
-    mFlinger->destroyConnection(mId);
-}
-
-sp<IMemoryHeap> BClient::getControlBlock() const {
-    return mCblk;
-}
-
-sp<ISurface> BClient::createSurface(
+sp<ISurface> UserClient::createSurface(
         ISurfaceComposerClient::surface_data_t* params, int pid,
         const String8& name,
         DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
-        uint32_t flags)
-{
-    return mFlinger->createSurface(mId, pid, name, params, display, w, h,
-            format, flags);
+        uint32_t flags) {
+    return 0;
 }
-
-status_t BClient::destroySurface(SurfaceID sid)
-{
-    sid |= (mId << 16); // add the client-part to id
-    return mFlinger->removeSurface(sid);
+status_t UserClient::destroySurface(SurfaceID sid) {
+    return INVALID_OPERATION;
 }
-
-status_t BClient::setState(int32_t count, const layer_state_t* states)
-{
-    return mFlinger->setClientState(mId, count, states);
+status_t UserClient::setState(int32_t count, const layer_state_t* states) {
+    return INVALID_OPERATION;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index d8fe98c..0bfc170 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -36,7 +36,6 @@
 
 #include "Barrier.h"
 #include "Layer.h"
-#include "Tokenizer.h"
 
 #include "MessageQueue.h"
 
@@ -48,54 +47,80 @@
 // ---------------------------------------------------------------------------
 
 class Client;
-class BClient;
 class DisplayHardware;
 class FreezeLock;
 class Layer;
+class LayerBlur;
+class LayerDim;
 class LayerBuffer;
 
-typedef int32_t ClientID;
-
 #define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
 #define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
 
 // ---------------------------------------------------------------------------
 
-class Client : public RefBase
+class Client : public BnSurfaceComposerClient
 {
 public:
-            Client(ClientID cid, const sp<SurfaceFlinger>& flinger);
-            ~Client();
+        Client(const sp<SurfaceFlinger>& flinger);
+        ~Client();
 
-            int32_t                 generateId(int pid);
-            void                    free(int32_t id);
-            status_t                bindLayer(const sp<LayerBaseClient>& layer, int32_t id);
+    status_t initCheck() const;
 
-    inline  bool                    isValid(int32_t i) const;
-    sp<LayerBaseClient>             getLayerUser(int32_t i) const;
-    
-    const Vector< wp<LayerBaseClient> >& getLayers() const { 
-        return mLayers; 
-    }
-    
-    const sp<IMemoryHeap>& getControlBlockMemory() const {
-        return mCblkHeap; 
-    }
-    
-    // pointer to this client's control block
-    SharedClient*           ctrlblk;
-    ClientID                cid;
+    // protected by SurfaceFlinger::mStateLock
+    ssize_t attachLayer(const sp<LayerBaseClient>& layer);
+    void detachLayer(const LayerBaseClient* layer);
+    sp<LayerBaseClient> getLayerUser(int32_t i) const;
 
-    
 private:
-    int getClientPid() const { return mPid; }
-        
-    int                             mPid;
-    uint32_t                        mBitmap;
-    SortedVector<uint8_t>           mInUse;
-    Vector< wp<LayerBaseClient> >   mLayers;
-    sp<IMemoryHeap>                 mCblkHeap;
-    sp<SurfaceFlinger>              mFlinger;
+
+    // ISurfaceComposerClient interface
+    virtual sp<IMemoryHeap> getControlBlock() const;
+    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;
+    virtual sp<ISurface> createSurface(
+            surface_data_t* params, int pid, const String8& name,
+            DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
+            uint32_t flags);
+    virtual status_t destroySurface(SurfaceID surfaceId);
+    virtual status_t setState(int32_t count, const layer_state_t* states);
+
+    DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers;
+    sp<SurfaceFlinger> mFlinger;
+    int32_t mNameGenerator;
+};
+
+class UserClient : public BnSurfaceComposerClient
+{
+public:
+    // pointer to this client's control block
+    SharedClient* ctrlblk;
+
+public:
+        UserClient(const sp<SurfaceFlinger>& flinger);
+        ~UserClient();
+
+    status_t initCheck() const;
+
+    // protected by SurfaceFlinger::mStateLock
+    void detachLayer(const Layer* layer);
+
+private:
+
+    // ISurfaceComposerClient interface
+    virtual sp<IMemoryHeap> getControlBlock() const;
+    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;
+    virtual sp<ISurface> createSurface(
+            surface_data_t* params, int pid, const String8& name,
+            DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
+            uint32_t flags);
+    virtual status_t destroySurface(SurfaceID surfaceId);
+    virtual status_t setState(int32_t count, const layer_state_t* states);
+
+    // atomic-ops
+    mutable volatile int32_t mBitmap;
+
+    sp<IMemoryHeap> mCblkHeap;
+    sp<SurfaceFlinger> mFlinger;
 };
 
 // ---------------------------------------------------------------------------
@@ -159,6 +184,7 @@
 
     // ISurfaceComposer interface
     virtual sp<ISurfaceComposerClient>  createConnection();
+    virtual sp<ISurfaceComposerClient>  createClientConnection();
     virtual sp<IMemoryHeap>             getCblk() const;
     virtual void                        bootFinished();
     virtual void                        openGlobalTransaction();
@@ -173,13 +199,14 @@
 
             overlay_control_device_t* getOverlayEngine() const;
 
-            
     status_t removeLayer(const sp<LayerBase>& layer);
     status_t addLayer(const sp<LayerBase>& layer);
     status_t invalidateLayerVisibility(const sp<LayerBase>& layer);
-    
+
+    sp<Layer> getLayer(const sp<ISurface>& sur) const;
+
 private:
-    friend class BClient;
+    friend class Client;
     friend class LayerBase;
     friend class LayerBuffer;
     friend class LayerBaseClient;
@@ -188,31 +215,33 @@
     friend class LayerBlur;
     friend class LayerDim;
 
-    sp<ISurface> createSurface(ClientID client, int pid, const String8& name,
+    sp<ISurface> createSurface(const sp<Client>& client,
+            int pid, const String8& name,
             ISurfaceComposerClient::surface_data_t* params,
             DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
             uint32_t flags);
 
-    sp<LayerBaseClient> createNormalSurfaceLocked(
+    sp<Layer> createNormalSurface(
             const sp<Client>& client, DisplayID display,
-            int32_t id, uint32_t w, uint32_t h, uint32_t flags,
+            uint32_t w, uint32_t h, uint32_t flags,
             PixelFormat& format);
 
-    sp<LayerBaseClient> createBlurSurfaceLocked(
+    sp<LayerBlur> createBlurSurface(
             const sp<Client>& client, DisplayID display,
-            int32_t id, uint32_t w, uint32_t h, uint32_t flags);
+            uint32_t w, uint32_t h, uint32_t flags);
 
-    sp<LayerBaseClient> createDimSurfaceLocked(
+    sp<LayerDim> createDimSurface(
             const sp<Client>& client, DisplayID display,
-            int32_t id, uint32_t w, uint32_t h, uint32_t flags);
+            uint32_t w, uint32_t h, uint32_t flags);
 
-    sp<LayerBaseClient> createPushBuffersSurfaceLocked(
+    sp<LayerBuffer> createPushBuffersSurface(
             const sp<Client>& client, DisplayID display,
-            int32_t id, uint32_t w, uint32_t h, uint32_t flags);
+            uint32_t w, uint32_t h, uint32_t flags);
 
-    status_t removeSurface(SurfaceID surface_id);
+    status_t removeSurface(const sp<Client>& client, SurfaceID sid);
     status_t destroySurface(const sp<LayerBaseClient>& layer);
-    status_t setClientState(ClientID cid, int32_t count, const layer_state_t* states);
+    status_t setClientState(const sp<Client>& client,
+            int32_t count, const layer_state_t* states);
 
 
     class LayerVector {
@@ -275,13 +304,11 @@
             void        unlockClients();
 
 
-            void        destroyConnection(ClientID cid);
-            sp<LayerBaseClient> getLayerUser_l(SurfaceID index) const;
+            ssize_t     addClientLayer(const sp<Client>& client,
+                    const sp<LayerBaseClient>& lbc);
             status_t    addLayer_l(const sp<LayerBase>& layer);
-            status_t    addClientLayer_l(const sp<LayerBaseClient>& lbc);
             status_t    removeLayer_l(const sp<LayerBase>& layer);
             status_t    purgatorizeLayer_l(const sp<LayerBase>& layer);
-            void        free_resources_l();
 
             uint32_t    getTransactionFlags(uint32_t flags);
             uint32_t    setTransactionFlags(uint32_t flags);
@@ -314,8 +341,7 @@
 
     status_t postMessageSync(const sp<MessageBase>& msg,
             nsecs_t reltime=0, uint32_t flags = 0);
-                
-                
+
                 // access must be protected by mStateLock
     mutable     Mutex                   mStateLock;
                 State                   mCurrentState;
@@ -324,14 +350,11 @@
     volatile    int32_t                 mTransactionCount;
                 Condition               mTransactionCV;
                 bool                    mResizeTransationPending;
-                
+
                 // protected by mStateLock (but we could use another lock)
-                Tokenizer                               mTokens;
-                DefaultKeyedVector<ClientID, sp<Client> >   mClientsMap;
-                DefaultKeyedVector<SurfaceID, sp<LayerBaseClient> >   mLayerMap;
-                GraphicPlane                            mGraphicPlanes[1];
-                bool                                    mLayersRemoved;
-                Vector< sp<Client> >                    mDisconnectedClients;
+                GraphicPlane                mGraphicPlanes[1];
+                bool                        mLayersRemoved;
+                DefaultKeyedVector< wp<IBinder>, wp<Layer> > mLayerMap;
 
                 // constant members (no synchronization needed for access)
                 sp<IMemoryHeap>             mServerHeap;
@@ -392,32 +415,6 @@
 };
 
 // ---------------------------------------------------------------------------
-
-class BClient : public BnSurfaceComposerClient
-{
-public:
-    BClient(SurfaceFlinger *flinger, ClientID cid,
-            const sp<IMemoryHeap>& cblk);
-    ~BClient();
-
-    // ISurfaceComposerClient interface
-    virtual sp<IMemoryHeap> getControlBlock() const;
-
-    virtual sp<ISurface> createSurface(
-            surface_data_t* params, int pid, const String8& name,
-            DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
-            uint32_t flags);
-
-    virtual status_t destroySurface(SurfaceID surfaceId);
-    virtual status_t setState(int32_t count, const layer_state_t* states);
-
-private:
-    ClientID            mId;
-    SurfaceFlinger*     mFlinger;
-    sp<IMemoryHeap>     mCblk;
-};
-
-// ---------------------------------------------------------------------------
 }; // namespace android
 
 #endif // ANDROID_SURFACE_FLINGER_H
diff --git a/libs/surfaceflinger/Tokenizer.cpp b/libs/surfaceflinger/Tokenizer.cpp
deleted file mode 100644
index be3a239..0000000
--- a/libs/surfaceflinger/Tokenizer.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-
-#include "Tokenizer.h"
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-ANDROID_BASIC_TYPES_TRAITS(Tokenizer::run_t)
-
-Tokenizer::Tokenizer()
-{
-}
-
-Tokenizer::Tokenizer(const Tokenizer& other)
-    : mRanges(other.mRanges)
-{
-}
-
-Tokenizer::~Tokenizer()
-{
-}
-
-uint32_t Tokenizer::acquire()
-{
-    if (!mRanges.size() || mRanges[0].first) {
-        _insertTokenAt(0,0);
-        return 0;
-    }
-    
-    // just extend the first run
-    const run_t& run = mRanges[0];
-    uint32_t token = run.first + run.length;
-    _insertTokenAt(token, 1);
-    return token;
-}
-
-bool Tokenizer::isAcquired(uint32_t token) const
-{
-    return (_indexOrderOf(token) >= 0);
-}
-
-status_t Tokenizer::reserve(uint32_t token)
-{
-    size_t o;
-    const ssize_t i = _indexOrderOf(token, &o);
-    if (i >= 0) {
-        return BAD_VALUE; // this token is already taken
-    }
-    ssize_t err = _insertTokenAt(token, o);
-    return (err<0) ? err : status_t(NO_ERROR);
-}
-
-status_t Tokenizer::release(uint32_t token)
-{
-    const ssize_t i = _indexOrderOf(token);
-    if (i >= 0) {
-        const run_t& run = mRanges[i];
-        if ((token >= run.first) && (token < run.first+run.length)) {
-            // token in this range, we need to split
-            run_t& run = mRanges.editItemAt(i);
-            if ((token == run.first) || (token == run.first+run.length-1)) {
-                if (token == run.first) {
-                    run.first += 1;
-                }
-                run.length -= 1;
-                if (run.length == 0) {
-                    // XXX: should we systematically remove a run that's empty?
-                    mRanges.removeItemsAt(i);
-                }
-            } else {
-                // split the run
-                run_t new_run;
-                new_run.first = token+1;
-                new_run.length = run.first+run.length - new_run.first;
-                run.length = token - run.first;
-                mRanges.insertAt(new_run, i+1);
-            }
-            return NO_ERROR;
-        }
-    }
-    return NAME_NOT_FOUND;
-}
-
-ssize_t Tokenizer::_indexOrderOf(uint32_t token, size_t* order) const
-{
-    // binary search
-    ssize_t err = NAME_NOT_FOUND;
-    ssize_t l = 0;
-    ssize_t h = mRanges.size()-1;
-    ssize_t mid;
-    const run_t* a = mRanges.array();
-    while (l <= h) {
-        mid = l + (h - l)/2;
-        const run_t* const curr = a + mid;
-        int c = 0;
-        if (token < curr->first)                        c = 1;
-        else if (token >= curr->first+curr->length)     c = -1;
-        if (c == 0) {
-            err = l = mid;
-            break;
-        } else if (c < 0) {
-            l = mid + 1;
-        } else {
-            h = mid - 1;
-        }
-    }
-    if (order) *order = l;
-    return err;
-}
-
-ssize_t Tokenizer::_insertTokenAt(uint32_t token, size_t index)
-{
-    const size_t c = mRanges.size();
-
-    if (index >= 1) {
-        // do we need to merge with the previous run?
-        run_t& p = mRanges.editItemAt(index-1);
-        if (p.first+p.length == token) {
-            p.length += 1;
-            if (index < c) {
-                const run_t& n = mRanges[index];
-                if (token+1 == n.first) {
-                    p.length += n.length;
-                    mRanges.removeItemsAt(index);
-                }
-            }
-            return index;
-        }
-    }
-    
-    if (index < c) {
-        // do we need to merge with the next run?
-        run_t& n = mRanges.editItemAt(index);
-        if (token+1 == n.first) {
-            n.first -= 1;
-            n.length += 1;
-            return index;
-        }
-    }
-
-    return mRanges.insertAt(run_t(token,1), index);
-}
-
-void Tokenizer::dump() const
-{
-    const run_t* ranges = mRanges.array();
-    const size_t c = mRanges.size();
-    printf("Tokenizer (%p, size = %d)\n", this, int(c));
-    for (size_t i=0 ; i<c ; i++) {
-        printf("%u: (%u, %u)\n", i,
-                uint32_t(ranges[i].first), uint32_t(ranges[i].length));
-    }
-}
-
-}; // namespace android
-
diff --git a/libs/surfaceflinger/Tokenizer.h b/libs/surfaceflinger/Tokenizer.h
deleted file mode 100644
index 6b3057d..0000000
--- a/libs/surfaceflinger/Tokenizer.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_TOKENIZER_H
-#define ANDROID_TOKENIZER_H
-
-#include <utils/Vector.h>
-#include <utils/Errors.h>
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-class Tokenizer
-{
-public:
-                Tokenizer();
-                Tokenizer(const Tokenizer& other);
-                ~Tokenizer();
-
-    uint32_t    acquire();
-    status_t    reserve(uint32_t token);
-    status_t    release(uint32_t token);
-    bool        isAcquired(uint32_t token) const;
-
-    void dump() const;
-
-    struct run_t {
-        run_t() {};
-        run_t(uint32_t f, uint32_t l) : first(f), length(l) {}
-        uint32_t    first;
-        uint32_t    length;
-    };
-private:
-    ssize_t _indexOrderOf(uint32_t token, size_t* order=0) const;
-    ssize_t _insertTokenAt(uint32_t token, size_t index);
-    Vector<run_t>   mRanges;
-};
-
-}; // namespace android
-
-// ----------------------------------------------------------------------------
-
-#endif // ANDROID_TOKENIZER_H
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index 50495c1..5c111f6 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -55,6 +55,15 @@
         return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
     }
 
+    virtual sp<ISurfaceComposerClient> createClientConnection()
+    {
+        uint32_t n;
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        remote()->transact(BnSurfaceComposer::CREATE_CLIENT_CONNECTION, data, &reply);
+        return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
+    }
+
     virtual sp<IMemoryHeap> getCblk() const
     {
         Parcel data, reply;
@@ -136,6 +145,11 @@
             sp<IBinder> b = createConnection()->asBinder();
             reply->writeStrongBinder(b);
         } break;
+        case CREATE_CLIENT_CONNECTION: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> b = createClientConnection()->asBinder();
+            reply->writeStrongBinder(b);
+        } break;
         case OPEN_GLOBAL_TRANSACTION: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             openGlobalTransaction();
diff --git a/libs/surfaceflinger_client/ISurfaceComposerClient.cpp b/libs/surfaceflinger_client/ISurfaceComposerClient.cpp
index 67c7df81..2cc1f8e 100644
--- a/libs/surfaceflinger_client/ISurfaceComposerClient.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposerClient.cpp
@@ -51,6 +51,7 @@
 
 enum {
     GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
+    GET_TOKEN,
     CREATE_SURFACE,
     DESTROY_SURFACE,
     SET_STATE
@@ -72,6 +73,15 @@
         return interface_cast<IMemoryHeap>(reply.readStrongBinder());
     }
 
+    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
+        data.writeStrongBinder(sur->asBinder());
+        remote()->transact(GET_TOKEN, data, &reply);
+        return reply.readInt32();
+    }
+
     virtual sp<ISurface> createSurface( surface_data_t* params,
                                         int pid,
                                         const String8& name,
@@ -132,6 +142,13 @@
             reply->writeStrongBinder(ctl->asBinder());
             return NO_ERROR;
         } break;
+        case GET_TOKEN: {
+            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
+            sp<ISurface> sur = interface_cast<ISurface>(data.readStrongBinder());
+            ssize_t token = getTokenForSurface(sur);
+            reply->writeInt32(token);
+            return NO_ERROR;
+        } break;
     }
 
     // these must be checked
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index 8d03145..1dd8642 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -58,7 +58,7 @@
 
 void SharedBufferStack::init(int32_t i)
 {
-    inUse = -1;
+    inUse = -2;
     status = NO_ERROR;
     identity = i;
 }
@@ -282,8 +282,10 @@
 }
 ssize_t SharedBufferServer::UnlockUpdate::operator()() {
     if (stack.inUse != lockedBuffer) {
-        LOGE("unlocking %d, but currently locked buffer is %d",
-                lockedBuffer, stack.inUse);
+        LOGE("unlocking %d, but currently locked buffer is %d "
+             "(identity=%d, token=%d)",
+                lockedBuffer, stack.inUse,
+                stack.identity, stack.token);
         return BAD_VALUE;
     }
     android_atomic_write(-1, &stack.inUse);
@@ -480,6 +482,7 @@
       mNumBuffers(num)
 {
     mSharedStack->init(identity);
+    mSharedStack->token = surface;
     mSharedStack->head = num-1;
     mSharedStack->available = num;
     mSharedStack->queued = 0;
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index ac4b198..6fe4c4a 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -238,14 +238,12 @@
 {
     uint32_t flags = 0;
     uint32_t format = 0;
-    SurfaceID token = -1;
     uint32_t identity = 0;
     uint32_t width = 0;
     uint32_t height = 0;
     sp<SurfaceComposerClient> client;
     sp<ISurface> sur;
     if (SurfaceControl::isValid(control)) {
-        token    = control->mToken;
         identity = control->mIdentity;
         client   = control->mClient;
         sur      = control->mSurface;
@@ -254,9 +252,7 @@
         format   = control->mFormat;
         flags    = control->mFlags;
     }
-    parcel->writeStrongBinder(client!=0  ? client->connection() : NULL);
-    parcel->writeStrongBinder(sur!=0     ? sur->asBinder()      : NULL);
-    parcel->writeInt32(token);
+    parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
     parcel->writeInt32(identity);
     parcel->writeInt32(width);
     parcel->writeInt32(height);
@@ -278,34 +274,92 @@
 //  Surface
 // ============================================================================
 
+class SurfaceClient : public Singleton<SurfaceClient>
+{
+    // all these attributes are constants
+    sp<ISurfaceComposer> mComposerService;
+    sp<ISurfaceComposerClient> mClient;
+    status_t mStatus;
+    SharedClient* mControl;
+    sp<IMemoryHeap> mControlMemory;
+
+    SurfaceClient()
+        : Singleton<SurfaceClient>(), mStatus(NO_INIT)
+    {
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        mComposerService = sf;
+        mClient = sf->createClientConnection();
+        if (mClient != NULL) {
+            mControlMemory = mClient->getControlBlock();
+            if (mControlMemory != NULL) {
+                mControl = static_cast<SharedClient *>(
+                        mControlMemory->getBase());
+                if (mControl) {
+                    mStatus = NO_ERROR;
+                }
+            }
+        }
+    }
+    friend class Singleton<SurfaceClient>;
+public:
+    status_t initCheck() const {
+        return mStatus;
+    }
+    SharedClient* getSharedClient() const {
+        return mControl;
+    }
+    ssize_t getTokenForSurface(const sp<ISurface>& sur) const {
+        // TODO: we could cache a few tokens here to avoid an IPC
+        return mClient->getTokenForSurface(sur);
+    }
+    void signalServer() const {
+        mComposerService->signal();
+    }
+};
+
+ANDROID_SINGLETON_STATIC_INSTANCE(SurfaceClient);
+
+// ---------------------------------------------------------------------------
+
 Surface::Surface(const sp<SurfaceControl>& surface)
-    : mSurface(surface->mSurface),
-      mToken(surface->mToken), mIdentity(surface->mIdentity),
-      mFormat(surface->mFormat), mFlags(surface->mFlags),
-      mBufferMapper(GraphicBufferMapper::get()), mSharedBufferClient(NULL),
+    : mBufferMapper(GraphicBufferMapper::get()),
+      mClient(SurfaceClient::getInstance()),
+      mSharedBufferClient(NULL),
       mInitCheck(NO_INIT),
+      mSurface(surface->mSurface),
+      mIdentity(surface->mIdentity),
+      mFormat(surface->mFormat), mFlags(surface->mFlags),
       mWidth(surface->mWidth), mHeight(surface->mHeight)
 {
-    mClient = new SurfaceClient(surface->mClient);
     init();
 }
 
-Surface::Surface(const Parcel& parcel)
-    :  mBufferMapper(GraphicBufferMapper::get()),
-       mSharedBufferClient(NULL), mInitCheck(NO_INIT)
+Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
+    : mBufferMapper(GraphicBufferMapper::get()),
+      mClient(SurfaceClient::getInstance()),
+      mSharedBufferClient(NULL),
+      mInitCheck(NO_INIT)
 {
-    sp<IBinder> conn = parcel.readStrongBinder();
-    mSurface    = interface_cast<ISurface>(parcel.readStrongBinder());
-    mToken      = parcel.readInt32();
+    mSurface    = interface_cast<ISurface>(ref);
     mIdentity   = parcel.readInt32();
     mWidth      = parcel.readInt32();
     mHeight     = parcel.readInt32();
     mFormat     = parcel.readInt32();
     mFlags      = parcel.readInt32();
-    mClient = new SurfaceClient(conn);
     init();
 }
 
+sp<Surface> Surface::readFromParcel(
+        const Parcel& data, const sp<Surface>& other)
+{
+    sp<Surface> result(other);
+    sp<IBinder> binder(data.readStrongBinder());
+    if (other==0 || binder != other->mSurface->asBinder()) {
+        result = new Surface(data, binder);
+    }
+    return result;
+}
+
 void Surface::init()
 {
     android_native_window_t::setSwapInterval  = setSwapInterval;
@@ -330,12 +384,14 @@
     mBuffers.setCapacity(2);
     mBuffers.insertAt(0, 2);
 
-    if (mClient != 0 && mClient->initCheck() == NO_ERROR) {
-        mSharedBufferClient = new SharedBufferClient(
-                mClient->getSharedClient(), mToken, 2, mIdentity);
+    if (mSurface != 0 && mClient.initCheck() == NO_ERROR) {
+        mToken = mClient.getTokenForSurface(mSurface);
+        if (mToken >= 0) {
+            mSharedBufferClient = new SharedBufferClient(
+                    mClient.getSharedClient(), mToken, 2, mIdentity);
+            mInitCheck = mClient.getSharedClient()->validate(mToken);
+        }
     }
-
-    mInitCheck = initCheck();
 }
 
 Surface::~Surface()
@@ -352,25 +408,11 @@
     // clear all references and trigger an IPC now, to make sure things
     // happen without delay, since these resources are quite heavy.
     mBuffers.clear();
-    mClient.clear();
     mSurface.clear();
     delete mSharedBufferClient;
     IPCThreadState::self()->flushCommands();
 }
 
-status_t Surface::initCheck() const
-{
-    if (mToken<0 || mClient==0 || mClient->initCheck() != NO_ERROR) {
-        return NO_INIT;
-    }
-    SharedClient const* cblk = mClient->getSharedClient();
-    if (cblk == 0) {
-        LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity);
-        return NO_INIT;
-    }
-    return cblk->validate(mToken);
-}
-
 bool Surface::isValid() {
     return mInitCheck == NO_ERROR;
 }
@@ -379,8 +421,7 @@
 {
     // check that we initialized ourself properly
     if (mInitCheck != NO_ERROR) {
-        LOGE("invalid token (%d, identity=%u) or client (%p)",
-                mToken, mIdentity, mClient.get());
+        LOGE("invalid token (%d, identity=%u)", mToken, mIdentity);
         return mInitCheck;
     }
 
@@ -413,12 +454,6 @@
     return NO_ERROR;
 }
 
-bool Surface::isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs) {
-    if (lhs == 0 || rhs == 0)
-        return false;
-    return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
-}
-
 sp<ISurface> Surface::getISurface() const {
     return mSurface;
 }
@@ -558,8 +593,8 @@
     LOGE_IF(err, "error queuing buffer %d (%s)", bufIdx, strerror(-err));
 
     if (err == NO_ERROR) {
-        // FIXME: can we avoid this IPC if we know there is one pending?
-        mClient->signalServer();
+        // TODO: can we avoid this IPC if we know there is one pending?
+        mClient.signalServer();
     }
     return err;
 }
diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
index 0670d20..5ac0d5d 100644
--- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp
+++ b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
@@ -42,36 +42,26 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-class ComposerService : public Singleton<ComposerService>
-{
-    // these are constants
-    sp<ISurfaceComposer> mComposerService;
-    sp<IMemoryHeap> mServerCblkMemory;
-    surface_flinger_cblk_t volatile* mServerCblk;
-
-    ComposerService() : Singleton<ComposerService>() {
-        const String16 name("SurfaceFlinger");
-        while (getService(name, &mComposerService) != NO_ERROR) {
-            usleep(250000);
-        }
-        mServerCblkMemory = mComposerService->getCblk();
-        mServerCblk = static_cast<surface_flinger_cblk_t volatile *>(
-                mServerCblkMemory->getBase());
-    }
-
-    friend class Singleton<ComposerService>;
-
-public:
-    static sp<ISurfaceComposer> getComposerService() {
-        return ComposerService::getInstance().mComposerService;
-    }
-    static surface_flinger_cblk_t const volatile * getControlBlock() {
-        return ComposerService::getInstance().mServerCblk;
-    }
-};
-
 ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService);
 
+ComposerService::ComposerService()
+: Singleton<ComposerService>() {
+    const String16 name("SurfaceFlinger");
+    while (getService(name, &mComposerService) != NO_ERROR) {
+        usleep(250000);
+    }
+    mServerCblkMemory = mComposerService->getCblk();
+    mServerCblk = static_cast<surface_flinger_cblk_t volatile *>(
+            mServerCblkMemory->getBase());
+}
+
+sp<ISurfaceComposer> ComposerService::getComposerService() {
+    return ComposerService::getInstance().mComposerService;
+}
+
+surface_flinger_cblk_t const volatile * ComposerService::getControlBlock() {
+    return ComposerService::getInstance().mServerCblk;
+}
 
 static inline sp<ISurfaceComposer> getComposerService() {
     return ComposerService::getComposerService();
@@ -557,41 +547,5 @@
 }
 
 // ----------------------------------------------------------------------------
-
-SurfaceClient::SurfaceClient(const sp<SurfaceComposerClient>& client)
-    : mStatus(NO_INIT), mControl(0)
-{
-    if (client != 0) {
-        sp<IBinder> conn = client->connection();
-        init(conn);
-    }
-}
-SurfaceClient::SurfaceClient(const sp<IBinder>& conn)
-    : mStatus(NO_INIT), mControl(0)
-{
-    init(conn);
-}
-void SurfaceClient::init(const sp<IBinder>& conn)
-{
-    mComposerService = getComposerService();
-    sp<ISurfaceComposerClient> sf(interface_cast<ISurfaceComposerClient>(conn));
-    if (sf != 0) {
-        mConnection = conn;
-        mControlMemory = sf->getControlBlock();
-        mControl = static_cast<SharedClient *>(mControlMemory->getBase());
-        mStatus = NO_ERROR;
-    }
-}
-status_t SurfaceClient::initCheck() const {
-    return mStatus;
-}
-SharedClient* SurfaceClient::getSharedClient() const {
-    return mControl;
-}
-void SurfaceClient::signalServer() const {
-    mComposerService->signal();
-}
-
-// ----------------------------------------------------------------------------
 }; // namespace android
 
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 35e4af3..3ddde38 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -38,7 +38,7 @@
 
 GraphicBuffer::GraphicBuffer()
     : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
-      mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
+      mInitCheck(NO_ERROR), mIndex(-1)
 {
     width  = 
     height = 
@@ -51,7 +51,7 @@
 GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h, 
         PixelFormat reqFormat, uint32_t reqUsage)
     : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
-      mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
+      mInitCheck(NO_ERROR), mIndex(-1)
 {
     width  = 
     height = 
@@ -67,7 +67,7 @@
         uint32_t inStride, native_handle_t* inHandle, bool keepOwnership)
     : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
       mBufferMapper(GraphicBufferMapper::get()),
-      mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
+      mInitCheck(NO_ERROR), mIndex(-1)
 {
     width  = w;
     height = h;
@@ -141,7 +141,6 @@
         this->height = h;
         this->format = format;
         this->usage  = reqUsage;
-        mVStride = 0;
     }
     return err;
 }
@@ -182,7 +181,6 @@
         sur->height = height;
         sur->stride = stride;
         sur->format = format;
-        sur->vstride = mVStride;
         sur->data = static_cast<GGLubyte*>(vaddr);
     }
     return res;
@@ -276,14 +274,6 @@
     return mIndex;
 }
 
-void GraphicBuffer::setVerticalStride(uint32_t vstride) {
-    mVStride = vstride;
-}
-
-uint32_t GraphicBuffer::getVerticalStride() const {
-    return mVStride;
-}
-
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index f1da72f..6e527d9 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -65,8 +65,9 @@
     public static final int FILE_TYPE_WMV     = 25;
     public static final int FILE_TYPE_ASF     = 26;
     public static final int FILE_TYPE_MKV     = 27;
+    public static final int FILE_TYPE_MP2TS   = 28;
     private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4;
-    private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_MKV;
+    private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_MP2TS;
     
     // Image file types
     public static final int FILE_TYPE_JPEG    = 31;
@@ -156,6 +157,8 @@
         addFileType("3GPP2", FILE_TYPE_3GPP2, "video/3gpp2");
         addFileType("MKV", FILE_TYPE_MKV, "video/x-matroska");
         addFileType("WEBM", FILE_TYPE_MKV, "video/x-matroska");
+        addFileType("TS", FILE_TYPE_MP2TS, "video/mp2ts");
+
         if (isWMVEnabled()) {
             addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv");
             addFileType("ASF", FILE_TYPE_ASF, "video/x-ms-asf");
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 8f6564a..7672f0f 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -344,7 +344,9 @@
  *     <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
  *          PlaybackCompleted}</p></td>
  *     <td>{Error}</p></td>
- *     <td>Successful invoke of this method does not change the state.</p></td></tr>
+ *     <td>Successful invoke of this method does not change the state. In order for the
+ *         target audio stream type to become effective, this method must be called before
+ *         prepare() or prepareAsync().</p></td></tr>
  * <tr><td>setDataSource </p></td>
  *     <td>{Idle} </p></td>
  *     <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
@@ -1112,7 +1114,9 @@
 
     /**
      * Sets the audio stream type for this MediaPlayer. See {@link AudioManager}
-     * for a list of stream types.
+     * for a list of stream types. Must call this method before prepare() or
+     * prepareAsync() in order for the target stream type to become effective
+     * thereafter.
      *
      * @param streamtype the audio stream type
      * @see android.media.AudioManager
diff --git a/media/libeffects/EffectEqualizer.cpp b/media/libeffects/EffectEqualizer.cpp
index c08f4f5..e39e595 100644
--- a/media/libeffects/EffectEqualizer.cpp
+++ b/media/libeffects/EffectEqualizer.cpp
@@ -114,7 +114,7 @@
 //--- Effect Library Interface Implementation
 //
 
-extern "C" int EffectQueryNumberEffects(int *pNumEffects) {
+extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects) {
     *pNumEffects = 1;
     gEffectIndex = 0;
     return 0;
diff --git a/media/libeffects/EffectReverb.c b/media/libeffects/EffectReverb.c
index 3181504..202f50b 100644
--- a/media/libeffects/EffectReverb.c
+++ b/media/libeffects/EffectReverb.c
@@ -18,7 +18,8 @@
 //
 #define LOG_NDEBUG 0
 #include <cutils/log.h>
-
+#include <stdlib.h>
+#include <string.h>
 #include <stdbool.h>
 #include "EffectReverb.h"
 #include "EffectsMath.h"
@@ -86,7 +87,7 @@
 
 /*--- Effect Library Interface Implementation ---*/
 
-int EffectQueryNumberEffects(int *pNumEffects) {
+int EffectQueryNumberEffects(uint32_t *pNumEffects) {
     *pNumEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *)
             - 1;
     gEffectIndex = 0;
diff --git a/media/libeffects/EffectReverb.h b/media/libeffects/EffectReverb.h
index cd14891..578e09e 100644
--- a/media/libeffects/EffectReverb.h
+++ b/media/libeffects/EffectReverb.h
@@ -292,7 +292,7 @@
  * Effect API
  *------------------------------------
 */
-int EffectQueryNumberEffects(int *pNumEffects);
+int EffectQueryNumberEffects(uint32_t *pNumEffects);
 int EffectQueryNext(effect_descriptor_t *pDescriptor);
 int EffectCreate(effect_uuid_t *effectUID, effect_interface_t *pInterface);
 int EffectRelease(effect_interface_t interface);
diff --git a/media/libeffects/EffectsFactory.c b/media/libeffects/EffectsFactory.c
index 35a10010..6800765 100644
--- a/media/libeffects/EffectsFactory.c
+++ b/media/libeffects/EffectsFactory.c
@@ -39,7 +39,7 @@
 static int init();
 static int loadLibrary(const char *libPath, int *handle);
 static int unloadLibrary(int handle);
-static int numEffectModules();
+static uint32_t numEffectModules();
 static int findEffect(effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc);
 static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len);
 
@@ -96,7 +96,7 @@
 //      Effect Factory Interface functions
 /////////////////////////////////////////////////
 
-int EffectQueryNumberEffects(int *pNumEffects)
+int EffectQueryNumberEffects(uint32_t *pNumEffects)
 {
     int ret = init();
     if (ret < 0) {
@@ -353,8 +353,8 @@
     effect_QueryNextEffect_t queryFx;
     effect_CreateEffect_t createFx;
     effect_ReleaseEffect_t releaseFx;
-    int numFx;
-    int fx;
+    uint32_t numFx;
+    uint32_t fx;
     int ret;
     list_elem_t *e, *descHead = NULL;
     lib_entry_t *l;
@@ -525,9 +525,9 @@
 
 
 
-int numEffectModules() {
+uint32_t numEffectModules() {
     list_elem_t *e = gLibraryList;
-    int cnt = 0;
+    uint32_t cnt = 0;
 
     // Reset pointers for EffectQueryNext()
     gCurLib = e;
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index fd2b1ce..a2436ab 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -45,7 +45,7 @@
 // ---------------------------------------------------------------------------
 
 AudioRecord::AudioRecord()
-    : mStatus(NO_INIT)
+    : mStatus(NO_INIT), mSessionId(0)
 {
 }
 
@@ -58,11 +58,12 @@
         uint32_t flags,
         callback_t cbf,
         void* user,
-        int notificationFrames)
-    : mStatus(NO_INIT)
+        int notificationFrames,
+        int sessionId)
+    : mStatus(NO_INIT), mSessionId(0)
 {
     mStatus = set(inputSource, sampleRate, format, channels,
-            frameCount, flags, cbf, user, notificationFrames);
+            frameCount, flags, cbf, user, notificationFrames, sessionId);
 }
 
 AudioRecord::~AudioRecord()
@@ -91,7 +92,8 @@
         callback_t cbf,
         void* user,
         int notificationFrames,
-        bool threadCanCallJava)
+        bool threadCanCallJava,
+        int sessionId)
 {
 
     LOGV("set(): sampleRate %d, channels %d, frameCount %d",sampleRate, channels, frameCount);
@@ -119,6 +121,7 @@
     if (!AudioSystem::isInputChannel(channels)) {
         return BAD_VALUE;
     }
+
     int channelCount = AudioSystem::popCount(channels);
 
     audio_io_handle_t input = AudioSystem::getInput(inputSource,
@@ -164,6 +167,8 @@
         notificationFrames = frameCount/2;
     }
 
+    mSessionId = sessionId;
+
     // create the IAudioRecord
     status_t status = openRecord(sampleRate, format, channelCount,
                                  frameCount, flags, input);
@@ -414,6 +419,7 @@
                                                        channelCount,
                                                        frameCount,
                                                        ((uint16_t)flags) << 16,
+                                                       &mSessionId,
                                                        &status);
     if (record == 0) {
         LOGE("AudioFlinger could not create record track, status: %d", status);
@@ -532,6 +538,11 @@
     return mInput;
 }
 
+int AudioRecord::getSessionId()
+{
+    return mSessionId;
+}
+
 // -------------------------------------------------------------------------
 
 ssize_t AudioRecord::read(void* buffer, size_t userSize)
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 5e6ce42..c77f551 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -364,6 +364,12 @@
     return result;
 }
 
+int AudioSystem::newAudioSessionId() {
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return 0;
+    return af->newAudioSessionId();
+}
+
 // ---------------------------------------------------------------------------
 
 void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index c350532..4b61131 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -58,7 +58,8 @@
         uint32_t flags,
         callback_t cbf,
         void* user,
-        int notificationFrames)
+        int notificationFrames,
+        int sessionId)
     : mStatus(NO_INIT)
 {
     mStatus = set(streamType, sampleRate, format, channels,
@@ -74,7 +75,8 @@
         uint32_t flags,
         callback_t cbf,
         void* user,
-        int notificationFrames)
+        int notificationFrames,
+        int sessionId)
     : mStatus(NO_INIT)
 {
     mStatus = set(streamType, sampleRate, format, channels,
@@ -110,7 +112,8 @@
         void* user,
         int notificationFrames,
         const sp<IMemory>& sharedBuffer,
-        bool threadCanCallJava)
+        bool threadCanCallJava,
+        int sessionId)
 {
 
     LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
@@ -171,8 +174,11 @@
 
     mVolume[LEFT] = 1.0f;
     mVolume[RIGHT] = 1.0f;
+    mSendLevel = 0;
     mFrameCount = frameCount;
     mNotificationFramesReq = notificationFrames;
+    mSessionId = sessionId;
+
     // create the IAudioTrack
     status_t status = createTrack(streamType, sampleRate, format, channelCount,
                                   frameCount, flags, sharedBuffer, output, true);
@@ -396,19 +402,49 @@
     return mMuted;
 }
 
-void AudioTrack::setVolume(float left, float right)
+status_t AudioTrack::setVolume(float left, float right)
 {
+    if (left > 1.0f || right > 1.0f) {
+        return BAD_VALUE;
+    }
+
     mVolume[LEFT] = left;
     mVolume[RIGHT] = right;
 
     // write must be atomic
-    mCblk->volumeLR = (int32_t(int16_t(left * 0x1000)) << 16) | int16_t(right * 0x1000);
+    mCblk->volumeLR = (uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000);
+
+    return NO_ERROR;
 }
 
 void AudioTrack::getVolume(float* left, float* right)
 {
-    *left  = mVolume[LEFT];
-    *right = mVolume[RIGHT];
+    if (left != NULL) {
+        *left  = mVolume[LEFT];
+    }
+    if (right != NULL) {
+        *right = mVolume[RIGHT];
+    }
+}
+
+status_t AudioTrack::setSendLevel(float level)
+{
+    if (level > 1.0f) {
+        return BAD_VALUE;
+    }
+
+    mSendLevel = level;
+
+    mCblk->sendLevel = uint16_t(level * 0x1000);
+
+    return NO_ERROR;
+}
+
+void AudioTrack::getSendLevel(float* level)
+{
+    if (level != NULL) {
+        *level  = mSendLevel;
+    }
 }
 
 status_t AudioTrack::setSampleRate(int rate)
@@ -563,6 +599,16 @@
             mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags);
 }
 
+int AudioTrack::getSessionId()
+{
+    return mSessionId;
+}
+
+status_t AudioTrack::attachAuxEffect(int effectId)
+{
+    return mAudioTrack->attachAuxEffect(effectId);
+}
+
 // -------------------------------------------------------------------------
 
 status_t AudioTrack::createTrack(
@@ -647,6 +693,7 @@
                                                       ((uint16_t)flags) << 16,
                                                       sharedBuffer,
                                                       output,
+                                                      &mSessionId,
                                                       &status);
 
     if (track == 0) {
@@ -672,7 +719,8 @@
         mCblk->stepUser(mCblk->frameCount);
     }
 
-    mCblk->volumeLR = (int32_t(int16_t(mVolume[LEFT] * 0x1000)) << 16) | int16_t(mVolume[RIGHT] * 0x1000);
+    mCblk->volumeLR = (uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | uint16_t(mVolume[LEFT] * 0x1000);
+    mCblk->sendLevel = uint16_t(mSendLevel * 0x1000);
     mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
     mCblk->waitTimeMs = 0;
     mRemainingFrames = mNotificationFramesAct;
@@ -1016,7 +1064,7 @@
     : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0),
     userBase(0), serverBase(0), buffers(0), frameCount(0),
     loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0),
-    flags(0)
+    flags(0), sendLevel(0)
 {
 }
 
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 47bcc12..f2a8db3 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -62,7 +62,14 @@
     SET_STREAM_OUTPUT,
     SET_VOICE_VOLUME,
     GET_RENDER_POSITION,
-    GET_INPUT_FRAMES_LOST
+    GET_INPUT_FRAMES_LOST,
+    NEW_AUDIO_SESSION_ID,
+    LOAD_EFFECT_LIBRARY,
+    UNLOAD_EFFECT_LIBRARY,
+    QUERY_NUM_EFFECTS,
+    QUERY_NEXT_EFFECT,
+    GET_EFFECT_DESCRIPTOR,
+    CREATE_EFFECT
 };
 
 class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -83,6 +90,7 @@
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 int output,
+                                int *sessionId,
                                 status_t *status)
     {
         Parcel data, reply;
@@ -97,10 +105,19 @@
         data.writeInt32(flags);
         data.writeStrongBinder(sharedBuffer->asBinder());
         data.writeInt32(output);
+        int lSessionId = 0;
+        if (sessionId != NULL) {
+            lSessionId = *sessionId;
+        }
+        data.writeInt32(lSessionId);
         status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
         if (lStatus != NO_ERROR) {
             LOGE("createTrack error: %s", strerror(-lStatus));
         } else {
+            lSessionId = reply.readInt32();
+            if (sessionId != NULL) {
+                *sessionId = lSessionId;
+            }
             lStatus = reply.readInt32();
             track = interface_cast<IAudioTrack>(reply.readStrongBinder());
         }
@@ -118,6 +135,7 @@
                                 int channelCount,
                                 int frameCount,
                                 uint32_t flags,
+                                int *sessionId,
                                 status_t *status)
     {
         Parcel data, reply;
@@ -130,10 +148,19 @@
         data.writeInt32(channelCount);
         data.writeInt32(frameCount);
         data.writeInt32(flags);
+        int lSessionId = 0;
+        if (sessionId != NULL) {
+            lSessionId = *sessionId;
+        }
+        data.writeInt32(lSessionId);
         status_t lStatus = remote()->transact(OPEN_RECORD, data, &reply);
         if (lStatus != NO_ERROR) {
             LOGE("openRecord error: %s", strerror(-lStatus));
         } else {
+            lSessionId = reply.readInt32();
+            if (sessionId != NULL) {
+                *sessionId = lSessionId;
+            }
             lStatus = reply.readInt32();
             record = interface_cast<IAudioRecord>(reply.readStrongBinder());
         }
@@ -497,6 +524,157 @@
         remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply);
         return reply.readInt32();
     }
+
+    virtual int newAudioSessionId()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        status_t status = remote()->transact(NEW_AUDIO_SESSION_ID, data, &reply);
+        int id = 0;
+        if (status == NO_ERROR) {
+            id = reply.readInt32();
+        }
+        return id;
+    }
+
+    virtual status_t loadEffectLibrary(const char *libPath, int *handle)
+    {
+        if (libPath == NULL || handle == NULL) {
+            return BAD_VALUE;
+        }
+        *handle = 0;
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeCString(libPath);
+        status_t status = remote()->transact(LOAD_EFFECT_LIBRARY, data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32();
+            if (status == NO_ERROR) {
+                *handle = reply.readInt32();
+            }
+        }
+        return status;
+    }
+
+    virtual status_t unloadEffectLibrary(int handle)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(handle);
+        status_t status = remote()->transact(UNLOAD_EFFECT_LIBRARY, data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32();
+        }
+        return status;
+    }
+
+    virtual status_t queryNumberEffects(uint32_t *numEffects)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        status_t status = remote()->transact(QUERY_NUM_EFFECTS, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = reply.readInt32();
+        if (status != NO_ERROR) {
+            return status;
+        }
+        if (numEffects) {
+            *numEffects = (uint32_t)reply.readInt32();
+        }
+        return NO_ERROR;
+    }
+
+    virtual status_t queryNextEffect(effect_descriptor_t *pDescriptor)
+    {
+        if (pDescriptor == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        status_t status = remote()->transact(QUERY_NEXT_EFFECT, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = reply.readInt32();
+        if (status != NO_ERROR) {
+            return status;
+        }
+        reply.read(pDescriptor, sizeof(effect_descriptor_t));
+        return NO_ERROR;
+    }
+
+    virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *pDescriptor)
+    {
+        if (pUuid == NULL || pDescriptor == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.write(pUuid, sizeof(effect_uuid_t));
+        status_t status = remote()->transact(GET_EFFECT_DESCRIPTOR, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = reply.readInt32();
+        if (status != NO_ERROR) {
+            return status;
+        }
+        reply.read(pDescriptor, sizeof(effect_descriptor_t));
+        return NO_ERROR;
+    }
+
+    virtual sp<IEffect> createEffect(pid_t pid,
+                                    effect_descriptor_t *pDesc,
+                                    const sp<IEffectClient>& client,
+                                    int32_t priority,
+                                    int output,
+                                    int sessionId,
+                                    status_t *status,
+                                    int *id,
+                                    int *enabled)
+    {
+        Parcel data, reply;
+        sp<IEffect> effect;
+
+        if (pDesc == NULL) {
+             return effect;
+             if (status) {
+                 *status = BAD_VALUE;
+             }
+         }
+
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(pid);
+        data.write(pDesc, sizeof(effect_descriptor_t));
+        data.writeStrongBinder(client->asBinder());
+        data.writeInt32(priority);
+        data.writeInt32(output);
+        data.writeInt32(sessionId);
+
+        status_t lStatus = remote()->transact(CREATE_EFFECT, data, &reply);
+        if (lStatus != NO_ERROR) {
+            LOGE("createEffect error: %s", strerror(-lStatus));
+        } else {
+            lStatus = reply.readInt32();
+            int tmp = reply.readInt32();
+            if (id) {
+                *id = tmp;
+            }
+            tmp = reply.readInt32();
+            if (enabled) {
+                *enabled = tmp;
+            }
+            effect = interface_cast<IEffect>(reply.readStrongBinder());
+            reply.read(pDesc, sizeof(effect_descriptor_t));
+        }
+        if (status) {
+            *status = lStatus;
+        }
+
+        return effect;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -518,10 +696,12 @@
             uint32_t flags = data.readInt32();
             sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
             int output = data.readInt32();
+            int sessionId = data.readInt32();
             status_t status;
             sp<IAudioTrack> track = createTrack(pid,
                     streamType, sampleRate, format,
-                    channelCount, bufferCount, flags, buffer, output, &status);
+                    channelCount, bufferCount, flags, buffer, output, &sessionId, &status);
+            reply->writeInt32(sessionId);
             reply->writeInt32(status);
             reply->writeStrongBinder(track->asBinder());
             return NO_ERROR;
@@ -535,9 +715,11 @@
             int channelCount = data.readInt32();
             size_t bufferCount = data.readInt32();
             uint32_t flags = data.readInt32();
+            int sessionId = data.readInt32();
             status_t status;
             sp<IAudioRecord> record = openRecord(pid, input,
-                    sampleRate, format, channelCount, bufferCount, flags, &status);
+                    sampleRate, format, channelCount, bufferCount, flags, &sessionId, &status);
+            reply->writeInt32(sessionId);
             reply->writeInt32(status);
             reply->writeStrongBinder(record->asBinder());
             return NO_ERROR;
@@ -768,7 +950,79 @@
             reply->writeInt32(getInputFramesLost(ioHandle));
             return NO_ERROR;
         } break;
+        case NEW_AUDIO_SESSION_ID: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32(newAudioSessionId());
+            return NO_ERROR;
+        } break;
+        case LOAD_EFFECT_LIBRARY: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int handle;
+            status_t status = loadEffectLibrary(data.readCString(), &handle);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->writeInt32(handle);
+            }
+            return NO_ERROR;
+        }
+        case UNLOAD_EFFECT_LIBRARY: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32(unloadEffectLibrary(data.readInt32()));
+            return NO_ERROR;
+        }
+        case QUERY_NUM_EFFECTS: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            uint32_t numEffects;
+            status_t status = queryNumberEffects(&numEffects);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->writeInt32((int32_t)numEffects);
+            }
+            return NO_ERROR;
+        }
+        case QUERY_NEXT_EFFECT: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            effect_descriptor_t desc;
+            status_t status = queryNextEffect(&desc);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->write(&desc, sizeof(effect_descriptor_t));
+            }
+            return NO_ERROR;
+        }
+        case GET_EFFECT_DESCRIPTOR: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            effect_uuid_t uuid;
+            data.read(&uuid, sizeof(effect_uuid_t));
+            effect_descriptor_t desc;
+            status_t status = getEffectDescriptor(&uuid, &desc);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->write(&desc, sizeof(effect_descriptor_t));
+            }
+            return NO_ERROR;
+        }
+        case CREATE_EFFECT: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            pid_t pid = data.readInt32();
+            effect_descriptor_t desc;
+            data.read(&desc, sizeof(effect_descriptor_t));
+            sp<IEffectClient> client = interface_cast<IEffectClient>(data.readStrongBinder());
+            int32_t priority = data.readInt32();
+            int output = data.readInt32();
+            int sessionId = data.readInt32();
+            status_t status;
+            int id;
+            int enabled;
 
+            sp<IEffect> effect = createEffect(pid, &desc, client, priority, output, sessionId, &status, &id, &enabled);
+            reply->writeInt32(status);
+            reply->writeInt32(id);
+            reply->writeInt32(enabled);
+            reply->writeStrongBinder(effect->asBinder());
+            reply->write(&desc, sizeof(effect_descriptor_t));
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index 01ffd75..bc8ff34 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -34,7 +34,8 @@
     STOP,
     FLUSH,
     MUTE,
-    PAUSE
+    PAUSE,
+    ATTACH_AUX_EFFECT
 };
 
 class BpAudioTrack : public BpInterface<IAudioTrack>
@@ -97,7 +98,21 @@
             cblk = interface_cast<IMemory>(reply.readStrongBinder());
         }
         return cblk;
-    }    
+    }
+
+    virtual status_t attachAuxEffect(int effectId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+        data.writeInt32(effectId);
+        status_t status = remote()->transact(ATTACH_AUX_EFFECT, data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32();
+        } else {
+            LOGW("attachAuxEffect() error: %s", strerror(-status));
+        }
+        return status;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
@@ -138,6 +153,11 @@
             pause();
             return NO_ERROR;
         }
+        case ATTACH_AUX_EFFECT: {
+            CHECK_INTERFACE(IAudioTrack, data, reply);
+            reply->writeInt32(attachAuxEffect(data.readInt32()));
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index f00fad8..6286046 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -80,11 +80,13 @@
         libstagefright_matroska \
         libstagefright_vpxdec \
         libvpx \
+        libstagefright_mpeg2ts \
 
 LOCAL_SHARED_LIBRARIES += \
         libstagefright_amrnb_common \
         libstagefright_enc_common \
-        libstagefright_avc_common
+        libstagefright_avc_common \
+        libstagefright_foundation \
 
 ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
 
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index c8834f8..264ac5f 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -75,6 +75,26 @@
     }
 }
 
+static int32_t getColorFormat(const char* colorFormat) {
+    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422SP)) {
+       return OMX_COLOR_FormatYUV422SemiPlanar;
+    }
+
+    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420SP)) {
+        return OMX_COLOR_FormatYUV420SemiPlanar;
+    }
+
+    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422I)) {
+        return OMX_COLOR_FormatYCbYCr;
+    }
+
+    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_RGB565)) {
+       return OMX_COLOR_Format16bitRGB565;
+    }
+
+    CHECK_EQ(0, "Unknown color format");
+}
+
 // static
 CameraSource *CameraSource::Create() {
     sp<Camera> camera = Camera::connect(0);
@@ -97,8 +117,6 @@
 
 CameraSource::CameraSource(const sp<Camera> &camera)
     : mCamera(camera),
-      mWidth(0),
-      mHeight(0),
       mFirstFrameTimeUs(0),
       mLastFrameTimestampUs(0),
       mNumFramesReceived(0),
@@ -108,8 +126,19 @@
     String8 s = mCamera->getParameters();
     printf("params: \"%s\"\n", s.string());
 
+    int32_t width, height;
     CameraParameters params(s);
-    params.getPreviewSize(&mWidth, &mHeight);
+    params.getPreviewSize(&width, &height);
+
+    const char *colorFormatStr = params.get(CameraParameters::KEY_VIDEO_FRAME_FORMAT);
+    CHECK(colorFormatStr != NULL);
+    int32_t colorFormat = getColorFormat(colorFormatStr);
+
+    mMeta = new MetaData;
+    mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
+    mMeta->setInt32(kKeyColorFormat, colorFormat);
+    mMeta->setInt32(kKeyWidth, width);
+    mMeta->setInt32(kKeyHeight, height);
 }
 
 CameraSource::~CameraSource() {
@@ -163,13 +192,7 @@
 }
 
 sp<MetaData> CameraSource::getFormat() {
-    sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
-    meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420SemiPlanar);
-    meta->setInt32(kKeyWidth, mWidth);
-    meta->setInt32(kKeyHeight, mHeight);
-
-    return meta;
+    return mMeta;
 }
 
 void CameraSource::signalBufferReturned(MediaBuffer *buffer) {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 475422d..b569a6b 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -19,6 +19,7 @@
 #include "include/MPEG4Extractor.h"
 #include "include/WAVExtractor.h"
 #include "include/OggExtractor.h"
+#include "include/MPEG2TSExtractor.h"
 
 #include "matroska/MatroskaExtractor.h"
 
@@ -97,6 +98,7 @@
     RegisterSniffer(SniffWAV);
     RegisterSniffer(SniffOgg);
     RegisterSniffer(SniffMatroska);
+    RegisterSniffer(SniffMPEG2TS);
 }
 
 // static
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 327a0ce..39d264c 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -38,5 +38,6 @@
 const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/wav";
 const char *MEDIA_MIMETYPE_CONTAINER_OGG = "application/ogg";
 const char *MEDIA_MIMETYPE_CONTAINER_MATROSKA = "video/x-matroska";
+const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS = "video/mp2ts";
 
 }  // namespace android
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 376d715..56e6136 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -23,6 +23,7 @@
 #include "include/MPEG4Extractor.h"
 #include "include/WAVExtractor.h"
 #include "include/OggExtractor.h"
+#include "include/MPEG2TSExtractor.h"
 
 #include "matroska/MatroskaExtractor.h"
 
@@ -73,6 +74,8 @@
         return new OggExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {
         return new MatroskaExtractor(source);
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
+        return new MPEG2TSExtractor(source);
     }
 
     return NULL;
diff --git a/media/libstagefright/Prefetcher.cpp b/media/libstagefright/Prefetcher.cpp
index 944a0c1..b6ed56b 100644
--- a/media/libstagefright/Prefetcher.cpp
+++ b/media/libstagefright/Prefetcher.cpp
@@ -58,13 +58,14 @@
     status_t mFinalStatus;
     int64_t mSeekTimeUs;
     int64_t mCacheDurationUs;
+    size_t mCacheSizeBytes;
     bool mPrefetcherStopped;
     bool mCurrentlyPrefetching;
 
     List<MediaBuffer *> mCachedBuffers;
 
     // Returns true iff source is currently caching.
-    bool getCacheDurationUs(int64_t *durationUs);
+    bool getCacheDurationUs(int64_t *durationUs, size_t *totalSize = NULL);
 
     void updateCacheDuration_l();
     void clearCache_l();
@@ -125,21 +126,31 @@
     return 0;
 }
 
-// Cache about 10secs for each source.
-static int64_t kMaxCacheDurationUs = 10000000ll;
+// Cache at most 1 min for each source.
+static int64_t kMaxCacheDurationUs = 60 * 1000000ll;
+
+// At the same time cache at most 5MB per source.
+static size_t kMaxCacheSizeBytes = 5 * 1024 * 1024;
+
+// If the amount of cached data drops below this,
+// fill the cache up to the max duration again.
+static int64_t kLowWaterDurationUs = 5000000ll;
 
 void Prefetcher::threadFunc() {
+    bool fillingCache = false;
+
     for (;;) {
         sp<PrefetchedSource> minSource;
+        int64_t minCacheDurationUs = -1;
 
         {
             Mutex::Autolock autoLock(mLock);
             if (mDone) {
                 break;
             }
-            mCondition.waitRelative(mLock, 10000000ll);
+            mCondition.waitRelative(
+                    mLock, fillingCache ? 10000000ll : 1000000000ll);
 
-            int64_t minCacheDurationUs = -1;
             ssize_t minIndex = -1;
             for (size_t i = 0; i < mSources.size(); ++i) {
                 sp<PrefetchedSource> source = mSources[i].promote();
@@ -149,11 +160,18 @@
                 }
 
                 int64_t cacheDurationUs;
-                if (!source->getCacheDurationUs(&cacheDurationUs)) {
+                size_t cacheSizeBytes;
+                if (!source->getCacheDurationUs(&cacheDurationUs, &cacheSizeBytes)) {
                     continue;
                 }
 
-                if (cacheDurationUs >= kMaxCacheDurationUs) {
+                if (cacheSizeBytes > kMaxCacheSizeBytes) {
+                    LOGI("max cache size reached");
+                    continue;
+                }
+
+                if (mSources.size() > 1 && cacheDurationUs >= kMaxCacheDurationUs) {
+                    LOGI("max duration reached, size = %d bytes", cacheSizeBytes);
                     continue;
                 }
 
@@ -165,14 +183,26 @@
             }
 
             if (minIndex < 0) {
+                if (fillingCache) {
+                    LOGV("[%p] done filling the cache, above high water mark.",
+                         this);
+                    fillingCache = false;
+                }
                 continue;
             }
         }
 
-        // Make sure not to hold the lock while calling into the source.
-        // The lock guards the list of sources, not the individual sources
-        // themselves.
-        minSource->cacheMore();
+        if (!fillingCache && minCacheDurationUs < kLowWaterDurationUs) {
+            LOGI("[%p] cache below low water mark, filling cache.", this);
+            fillingCache = true;
+        }
+
+        if (fillingCache) {
+            // Make sure not to hold the lock while calling into the source.
+            // The lock guards the list of sources, not the individual sources
+            // themselves.
+            minSource->cacheMore();
+        }
     }
 
     Mutex::Autolock autoLock(mLock);
@@ -250,6 +280,7 @@
       mReachedEOS(false),
       mSeekTimeUs(0),
       mCacheDurationUs(0),
+      mCacheSizeBytes(0),
       mPrefetcherStopped(false),
       mCurrentlyPrefetching(false) {
 }
@@ -323,6 +354,7 @@
     *out = *mCachedBuffers.begin();
     mCachedBuffers.erase(mCachedBuffers.begin());
     updateCacheDuration_l();
+    mCacheSizeBytes -= (*out)->size();
 
     return OK;
 }
@@ -331,10 +363,14 @@
     return mSource->getFormat();
 }
 
-bool PrefetchedSource::getCacheDurationUs(int64_t *durationUs) {
+bool PrefetchedSource::getCacheDurationUs(
+        int64_t *durationUs, size_t *totalSize) {
     Mutex::Autolock autoLock(mLock);
 
     *durationUs = mCacheDurationUs;
+    if (totalSize != NULL) {
+        *totalSize = mCacheSizeBytes;
+    }
 
     if (!mStarted || mReachedEOS) {
         return false;
@@ -397,6 +433,7 @@
 
     mCachedBuffers.push_back(copy);
     updateCacheDuration_l();
+    mCacheSizeBytes += copy->size();
 
     mCurrentlyPrefetching = false;
     mCondition.signal();
@@ -425,6 +462,7 @@
     }
 
     updateCacheDuration_l();
+    mCacheSizeBytes = 0;
 }
 
 void PrefetchedSource::onPrefetcherStopped() {
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 2829638..1629e9f 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -39,7 +39,7 @@
         ".mp3", ".mp4", ".m4a", ".3gp", ".3gpp", ".3g2", ".3gpp2",
         ".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
         ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
-        ".mkv", ".mka", ".webm"
+        ".mkv", ".mka", ".webm", ".ts"
     };
     static const size_t kNumValidExtensions =
         sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
diff --git a/media/libstagefright/foundation/AAtomizer.cpp b/media/libstagefright/foundation/AAtomizer.cpp
new file mode 100644
index 0000000..b7b9e9f9
--- /dev/null
+++ b/media/libstagefright/foundation/AAtomizer.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+
+#include "AAtomizer.h"
+
+namespace android {
+
+// static
+AAtomizer AAtomizer::gAtomizer;
+
+// static
+const char *AAtomizer::Atomize(const char *name) {
+    return gAtomizer.atomize(name);
+}
+
+AAtomizer::AAtomizer() {
+    for (size_t i = 0; i < 128; ++i) {
+        mAtoms.push(List<AString>());
+    }
+}
+
+const char *AAtomizer::atomize(const char *name) {
+    Mutex::Autolock autoLock(mLock);
+
+    const size_t n = mAtoms.size();
+    size_t index = AAtomizer::Hash(name) % n;
+    List<AString> &entry = mAtoms.editItemAt(index);
+    List<AString>::iterator it = entry.begin();
+    while (it != entry.end()) {
+        if ((*it) == name) {
+            return (*it).c_str();
+        }
+        ++it;
+    }
+
+    entry.push_back(AString(name));
+
+    return (*--entry.end()).c_str();
+}
+
+// static
+uint32_t AAtomizer::Hash(const char *s) {
+    uint32_t sum = 0;
+    while (*s != '\0') {
+        sum = (sum * 31) + *s;
+        ++s;
+    }
+
+    return sum;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/foundation/ABuffer.cpp b/media/libstagefright/foundation/ABuffer.cpp
new file mode 100644
index 0000000..6173db4
--- /dev/null
+++ b/media/libstagefright/foundation/ABuffer.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#include "ABuffer.h"
+
+#include "ADebug.h"
+#include "ALooper.h"
+#include "AMessage.h"
+
+namespace android {
+
+ABuffer::ABuffer(size_t capacity)
+    : mData(malloc(capacity)),
+      mCapacity(capacity),
+      mRangeOffset(0),
+      mRangeLength(capacity),
+      mInt32Data(0),
+      mOwnsData(true) {
+}
+
+ABuffer::ABuffer(void *data, size_t capacity)
+    : mData(data),
+      mCapacity(capacity),
+      mRangeOffset(0),
+      mRangeLength(capacity),
+      mInt32Data(0),
+      mOwnsData(false) {
+}
+
+ABuffer::~ABuffer() {
+    if (mOwnsData) {
+        if (mData != NULL) {
+            free(mData);
+            mData = NULL;
+        }
+    }
+
+    if (mFarewell != NULL) {
+        mFarewell->post();
+    }
+}
+
+void ABuffer::setRange(size_t offset, size_t size) {
+    CHECK_LE(offset, mCapacity);
+    CHECK_LE(offset + size, mCapacity);
+
+    mRangeOffset = offset;
+    mRangeLength = size;
+}
+
+void ABuffer::setFarewellMessage(const sp<AMessage> msg) {
+    mFarewell = msg;
+}
+
+sp<AMessage> ABuffer::meta() {
+    if (mMeta == NULL) {
+        mMeta = new AMessage;
+    }
+    return mMeta;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/foundation/ADebug.cpp b/media/libstagefright/foundation/ADebug.cpp
new file mode 100644
index 0000000..16f8b22
--- /dev/null
+++ b/media/libstagefright/foundation/ADebug.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#include "ADebug.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef ANDROID
+#include <cutils/log.h>
+#endif
+
+namespace android {
+
+Logger::Logger(LogType type)
+    : mLogType(type) {
+    switch (mLogType) {
+        case VERBOSE:
+            mMessage = "V ";
+            break;
+        case INFO:
+            mMessage = "I ";
+            break;
+        case WARNING:
+            mMessage = "W ";
+            break;
+        case ERROR:
+            mMessage = "E ";
+            break;
+        case FATAL:
+            mMessage = "F ";
+            break;
+
+        default:
+            break;
+    }
+}
+
+Logger::~Logger() {
+    if (mLogType == VERBOSE) {
+        return;
+    }
+
+    mMessage.append("\n");
+
+#if defined(ANDROID) && 1
+    LOG_PRI(ANDROID_LOG_INFO, "ADebug", "%s", mMessage.c_str());
+#else
+    fprintf(stderr, mMessage.c_str());
+    fflush(stderr);
+#endif
+
+    if (mLogType == FATAL) {
+        abort();
+    }
+}
+
+const char *LeafName(const char *s) {
+    const char *lastSlash = strrchr(s, '/');
+    return lastSlash != NULL ? lastSlash + 1 : s;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp
new file mode 100644
index 0000000..831fa2a
--- /dev/null
+++ b/media/libstagefright/foundation/ALooper.cpp
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ALooper"
+#include <utils/Log.h>
+
+#include <sys/time.h>
+
+#include "ALooper.h"
+
+#include "AHandler.h"
+#include "ALooperRoster.h"
+#include "AMessage.h"
+
+namespace android {
+
+ALooperRoster gLooperRoster;
+
+struct ALooper::LooperThread : public Thread {
+    LooperThread(ALooper *looper)
+        : mLooper(looper) {
+    }
+
+    virtual bool threadLoop() {
+        return mLooper->loop();
+    }
+
+protected:
+    virtual ~LooperThread() {}
+
+private:
+    ALooper *mLooper;
+
+    DISALLOW_EVIL_CONSTRUCTORS(LooperThread);
+};
+
+// static
+int64_t ALooper::GetNowUs() {
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+
+    return (int64_t)tv.tv_sec * 1000000ll + tv.tv_usec;
+}
+
+ALooper::ALooper()
+    : mRunningLocally(false) {
+}
+
+ALooper::~ALooper() {
+    stop();
+}
+
+ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {
+    return gLooperRoster.registerHandler(this, handler);
+}
+
+void ALooper::unregisterHandler(handler_id handlerID) {
+    gLooperRoster.unregisterHandler(handlerID);
+}
+
+status_t ALooper::start(bool runOnCallingThread) {
+    if (runOnCallingThread) {
+        {
+            Mutex::Autolock autoLock(mLock);
+
+            if (mThread != NULL || mRunningLocally) {
+                return INVALID_OPERATION;
+            }
+
+            mRunningLocally = true;
+        }
+
+        do {
+        } while (loop());
+
+        return OK;
+    }
+
+    Mutex::Autolock autoLock(mLock);
+
+    if (mThread != NULL || mRunningLocally) {
+        return INVALID_OPERATION;
+    }
+
+    mThread = new LooperThread(this);
+
+    status_t err = mThread->run("ALooper");
+    if (err != OK) {
+        mThread.clear();
+    }
+
+    return err;
+}
+
+status_t ALooper::stop() {
+    sp<LooperThread> thread;
+    bool runningLocally;
+
+    {
+        Mutex::Autolock autoLock(mLock);
+
+        thread = mThread;
+        runningLocally = mRunningLocally;
+        mThread.clear();
+        mRunningLocally = false;
+    }
+
+    if (thread == NULL && !runningLocally) {
+        return INVALID_OPERATION;
+    }
+
+    if (thread != NULL) {
+        thread->requestExit();
+    }
+
+    mQueueChangedCondition.signal();
+
+    if (!runningLocally) {
+        thread->requestExitAndWait();
+    }
+
+    return OK;
+}
+
+void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {
+    Mutex::Autolock autoLock(mLock);
+
+    int64_t whenUs;
+    if (delayUs > 0) {
+        whenUs = GetNowUs() + delayUs;
+    } else {
+        whenUs = GetNowUs();
+    }
+
+    List<Event>::iterator it = mEventQueue.begin();
+    while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) {
+        ++it;
+    }
+
+    Event event;
+    event.mWhenUs = whenUs;
+    event.mMessage = msg;
+
+    if (it == mEventQueue.begin()) {
+        mQueueChangedCondition.signal();
+    }
+
+    mEventQueue.insert(it, event);
+}
+
+bool ALooper::loop() {
+    Event event;
+
+    {
+        Mutex::Autolock autoLock(mLock);
+        if (mThread == NULL && !mRunningLocally) {
+            return false;
+        }
+        if (mEventQueue.empty()) {
+            mQueueChangedCondition.wait(mLock);
+            return true;
+        }
+        int64_t whenUs = (*mEventQueue.begin()).mWhenUs;
+        int64_t nowUs = GetNowUs();
+
+        if (whenUs > nowUs) {
+            int64_t delayUs = whenUs - nowUs;
+            mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);
+
+            return true;
+        }
+
+        event = *mEventQueue.begin();
+        mEventQueue.erase(mEventQueue.begin());
+    }
+
+    gLooperRoster.deliverMessage(event.mMessage);
+
+    return true;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp
new file mode 100644
index 0000000..5bb1cf9
--- /dev/null
+++ b/media/libstagefright/foundation/ALooperRoster.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ALooperRoster"
+#include <utils/Log.h>
+
+#include "ALooperRoster.h"
+
+#include "ADebug.h"
+#include "AHandler.h"
+#include "AMessage.h"
+
+namespace android {
+
+ALooperRoster::ALooperRoster()
+    : mNextHandlerID(1) {
+}
+
+ALooper::handler_id ALooperRoster::registerHandler(
+        const sp<ALooper> looper, const sp<AHandler> &handler) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (handler->id() != 0) {
+        CHECK(!"A handler must only be registered once.");
+        return INVALID_OPERATION;
+    }
+
+    HandlerInfo info;
+    info.mLooper = looper;
+    info.mHandler = handler;
+    ALooper::handler_id handlerID = mNextHandlerID++;
+    mHandlers.add(handlerID, info);
+
+    handler->setID(handlerID);
+
+    return handlerID;
+}
+
+void ALooperRoster::unregisterHandler(ALooper::handler_id handlerID) {
+    Mutex::Autolock autoLock(mLock);
+
+    ssize_t index = mHandlers.indexOfKey(handlerID);
+    CHECK(index >= 0);
+
+    const HandlerInfo &info = mHandlers.valueAt(index);
+    info.mHandler->setID(0);
+
+    mHandlers.removeItemsAt(index);
+}
+
+void ALooperRoster::postMessage(
+        const sp<AMessage> &msg, int64_t delayUs) {
+    Mutex::Autolock autoLock(mLock);
+
+    ssize_t index = mHandlers.indexOfKey(msg->target());
+
+    if (index < 0) {
+        LOG(WARNING) << "failed to post message. Target handler not registered.";
+        return;
+    }
+
+    const HandlerInfo &info = mHandlers.valueAt(index);
+    info.mLooper->post(msg, delayUs);
+}
+
+void ALooperRoster::deliverMessage(const sp<AMessage> &msg) {
+    sp<AHandler> handler;
+
+    {
+        Mutex::Autolock autoLock(mLock);
+
+        ssize_t index = mHandlers.indexOfKey(msg->target());
+
+        if (index < 0) {
+            LOG(WARNING) << "failed to deliver message. Target handler not registered.";
+            return;
+        }
+
+        const HandlerInfo &info = mHandlers.valueAt(index);
+        handler = info.mHandler;
+    }
+
+    handler->onMessageReceived(msg);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
new file mode 100644
index 0000000..dfd1ae3
--- /dev/null
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -0,0 +1,241 @@
+/*
+ * 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.
+ */
+
+#include "AMessage.h"
+
+#include "AAtomizer.h"
+#include "ADebug.h"
+#include "ALooperRoster.h"
+#include "AString.h"
+
+namespace android {
+
+AMessage::AMessage(uint32_t what, ALooper::handler_id target)
+    : mWhat(what),
+      mTarget(target),
+      mNumItems(0) {
+}
+
+AMessage::~AMessage() {
+    clear();
+}
+
+void AMessage::setWhat(uint32_t what) {
+    mWhat = what;
+}
+
+uint32_t AMessage::what() const {
+    return mWhat;
+}
+
+void AMessage::setTarget(ALooper::handler_id handlerID) {
+    mTarget = handlerID;
+}
+
+ALooper::handler_id AMessage::target() const {
+    return mTarget;
+}
+
+void AMessage::clear() {
+    for (size_t i = 0; i < mNumItems; ++i) {
+        Item *item = &mItems[i];
+        freeItem(item);
+    }
+    mNumItems = 0;
+}
+
+void AMessage::freeItem(Item *item) {
+    switch (item->mType) {
+        case kTypeString:
+        {
+            delete item->u.stringValue;
+            break;
+        }
+
+        case kTypeObject:
+        case kTypeMessage:
+        {
+            if (item->u.refValue != NULL) {
+                item->u.refValue->decStrong(this);
+            }
+            break;
+        }
+
+        default:
+            break;
+    }
+}
+
+AMessage::Item *AMessage::allocateItem(const char *name) {
+    name = AAtomizer::Atomize(name);
+
+    size_t i = 0;
+    while (i < mNumItems && mItems[i].mName != name) {
+        ++i;
+    }
+
+    Item *item;
+
+    if (i < mNumItems) {
+        item = &mItems[i];
+        freeItem(item);
+    } else {
+        CHECK(mNumItems < kMaxNumItems);
+        i = mNumItems++;
+        item = &mItems[i];
+
+        item->mName = name;
+    }
+
+    return item;
+}
+
+const AMessage::Item *AMessage::findItem(
+        const char *name, Type type) const {
+    name = AAtomizer::Atomize(name);
+
+    for (size_t i = 0; i < mNumItems; ++i) {
+        const Item *item = &mItems[i];
+
+        if (item->mName == name) {
+            return item->mType == type ? item : NULL;
+        }
+    }
+
+    return NULL;
+}
+
+#define BASIC_TYPE(NAME,FIELDNAME,TYPENAME)                             \
+void AMessage::set##NAME(const char *name, TYPENAME value) {            \
+    Item *item = allocateItem(name);                                    \
+                                                                        \
+    item->mType = kType##NAME;                                          \
+    item->u.FIELDNAME = value;                                          \
+}                                                                       \
+                                                                        \
+bool AMessage::find##NAME(const char *name, TYPENAME *value) const {    \
+    const Item *item = findItem(name, kType##NAME);                     \
+    if (item) {                                                         \
+        *value = item->u.FIELDNAME;                                     \
+        return true;                                                    \
+    }                                                                   \
+    return false;                                                       \
+}
+
+BASIC_TYPE(Int32,int32Value,int32_t)
+BASIC_TYPE(Int64,int64Value,int64_t)
+BASIC_TYPE(Size,sizeValue,size_t)
+BASIC_TYPE(Float,floatValue,float)
+BASIC_TYPE(Double,doubleValue,double)
+BASIC_TYPE(Pointer,ptrValue,void *)
+
+#undef BASIC_TYPE
+
+void AMessage::setString(
+        const char *name, const char *s, ssize_t len) {
+    Item *item = allocateItem(name);
+    item->mType = kTypeString;
+    item->u.stringValue = new AString(s, len < 0 ? strlen(s) : len);
+}
+
+void AMessage::setObject(const char *name, const sp<RefBase> &obj) {
+    Item *item = allocateItem(name);
+    item->mType = kTypeObject;
+
+    if (obj != NULL) { obj->incStrong(this); }
+    item->u.refValue = obj.get();
+}
+
+void AMessage::setMessage(const char *name, const sp<AMessage> &obj) {
+    Item *item = allocateItem(name);
+    item->mType = kTypeMessage;
+
+    if (obj != NULL) { obj->incStrong(this); }
+    item->u.refValue = obj.get();
+}
+
+bool AMessage::findString(const char *name, AString *value) const {
+    const Item *item = findItem(name, kTypeString);
+    if (item) {
+        *value = *item->u.stringValue;
+        return true;
+    }
+    return false;
+}
+
+bool AMessage::findObject(const char *name, sp<RefBase> *obj) const {
+    const Item *item = findItem(name, kTypeObject);
+    if (item) {
+        *obj = item->u.refValue;
+        return true;
+    }
+    return false;
+}
+
+bool AMessage::findMessage(const char *name, sp<AMessage> *obj) const {
+    const Item *item = findItem(name, kTypeMessage);
+    if (item) {
+        *obj = static_cast<AMessage *>(item->u.refValue);
+        return true;
+    }
+    return false;
+}
+
+void AMessage::post(int64_t delayUs) {
+    extern ALooperRoster gLooperRoster;
+
+    gLooperRoster.postMessage(this, delayUs);
+}
+
+sp<AMessage> AMessage::dup() const {
+    sp<AMessage> msg = new AMessage(mWhat, mTarget);
+    msg->mNumItems = mNumItems;
+
+    for (size_t i = 0; i < mNumItems; ++i) {
+        const Item *from = &mItems[i];
+        Item *to = &msg->mItems[i];
+
+        to->mName = from->mName;
+        to->mType = from->mType;
+
+        switch (from->mType) {
+            case kTypeString:
+            {
+                to->u.stringValue =
+                    new AString(*from->u.stringValue);
+                break;
+            }
+
+            case kTypeObject:
+            case kTypeMessage:
+            {
+                to->u.refValue = from->u.refValue;
+                to->u.refValue->incStrong(msg.get());
+                break;
+            }
+
+            default:
+            {
+                to->u = from->u;
+                break;
+            }
+        }
+    }
+
+    return msg;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp
new file mode 100644
index 0000000..61b76cf
--- /dev/null
+++ b/media/libstagefright/foundation/AString.cpp
@@ -0,0 +1,331 @@
+/*
+ * 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.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ADebug.h"
+#include "AString.h"
+
+namespace android {
+
+// static
+const char *AString::kEmptyString = "";
+
+AString::AString()
+    : mData((char *)kEmptyString),
+      mSize(0),
+      mAllocSize(1) {
+}
+
+AString::AString(const char *s)
+    : mData(NULL),
+      mSize(0),
+      mAllocSize(1) {
+    setTo(s);
+}
+
+AString::AString(const char *s, size_t size)
+    : mData(NULL),
+      mSize(0),
+      mAllocSize(1) {
+    setTo(s, size);
+}
+
+AString::AString(const AString &from)
+    : mData(NULL),
+      mSize(0),
+      mAllocSize(1) {
+    setTo(from, 0, from.size());
+}
+
+AString::AString(const AString &from, size_t offset, size_t n)
+    : mData(NULL),
+      mSize(0),
+      mAllocSize(1) {
+    setTo(from, offset, n);
+}
+
+AString::~AString() {
+    clear();
+}
+
+AString &AString::operator=(const AString &from) {
+    if (&from != this) {
+        setTo(from, 0, from.size());
+    }
+
+    return *this;
+}
+
+size_t AString::size() const {
+    return mSize;
+}
+
+const char *AString::c_str() const {
+    return mData;
+}
+
+bool AString::empty() const {
+    return mSize == 0;
+}
+
+void AString::setTo(const char *s) {
+    setTo(s, strlen(s));
+}
+
+void AString::setTo(const char *s, size_t size) {
+    clear();
+    append(s, size);
+}
+
+void AString::setTo(const AString &from, size_t offset, size_t n) {
+    CHECK(&from != this);
+
+    clear();
+    setTo(from.mData + offset, n);
+}
+
+void AString::clear() {
+    if (mData && mData != kEmptyString) {
+        free(mData);
+        mData = NULL;
+    }
+
+    mData = (char *)kEmptyString;
+    mSize = 0;
+    mAllocSize = 1;
+}
+
+size_t AString::hash() const {
+    size_t x = 0;
+    for (size_t i = 0; i < mSize; ++i) {
+        x = (x * 31) + mData[i];
+    }
+
+    return x;
+}
+
+bool AString::operator==(const AString &other) const {
+    return mSize == other.mSize && !memcmp(mData, other.mData, mSize);
+}
+
+void AString::trim() {
+    makeMutable();
+
+    size_t i = 0;
+    while (i < mSize && isspace(mData[i])) {
+        ++i;
+    }
+
+    size_t j = mSize;
+    while (j > i && isspace(mData[j - 1])) {
+        --j;
+    }
+
+    memmove(mData, &mData[i], j - i);
+    mSize = j - i;
+    mData[mSize] = '\0';
+}
+
+void AString::erase(size_t start, size_t n) {
+    CHECK_LT(start, mSize);
+    CHECK_LE(start + n, mSize);
+
+    makeMutable();
+
+    memmove(&mData[start], &mData[start + n], mSize - start - n);
+    mSize -= n;
+    mData[mSize] = '\0';
+}
+
+void AString::makeMutable() {
+    if (mData == kEmptyString) {
+        mData = strdup(kEmptyString);
+    }
+}
+
+void AString::append(const char *s) {
+    append(s, strlen(s));
+}
+
+void AString::append(const char *s, size_t size) {
+    makeMutable();
+
+    if (mSize + size + 1 > mAllocSize) {
+        mAllocSize = (mAllocSize + size + 31) & -32;
+        mData = (char *)realloc(mData, mAllocSize);
+        CHECK(mData != NULL);
+    }
+
+    memcpy(&mData[mSize], s, size);
+    mSize += size;
+    mData[mSize] = '\0';
+}
+
+void AString::append(const AString &from) {
+    append(from.c_str(), from.size());
+}
+
+void AString::append(const AString &from, size_t offset, size_t n) {
+    append(from.c_str() + offset, n);
+}
+
+void AString::append(int x) {
+    char s[16];
+    sprintf(s, "%d", x);
+
+    append(s);
+}
+
+void AString::append(unsigned x) {
+    char s[16];
+    sprintf(s, "%u", x);
+
+    append(s);
+}
+
+void AString::append(long x) {
+    char s[16];
+    sprintf(s, "%ld", x);
+
+    append(s);
+}
+
+void AString::append(unsigned long x) {
+    char s[16];
+    sprintf(s, "%lu", x);
+
+    append(s);
+}
+
+void AString::append(long long x) {
+    char s[32];
+    sprintf(s, "%lld", x);
+
+    append(s);
+}
+
+void AString::append(unsigned long long x) {
+    char s[32];
+    sprintf(s, "%llu", x);
+
+    append(s);
+}
+
+void AString::append(float x) {
+    char s[16];
+    sprintf(s, "%f", x);
+
+    append(s);
+}
+
+void AString::append(double x) {
+    char s[16];
+    sprintf(s, "%f", x);
+
+    append(s);
+}
+
+void AString::append(void *x) {
+    char s[16];
+    sprintf(s, "%p", x);
+
+    append(s);
+}
+
+ssize_t AString::find(const char *substring, size_t start) const {
+    CHECK_LE(start, size());
+
+    const char *match = strstr(mData + start, substring);
+
+    if (match == NULL) {
+        return -1;
+    }
+
+    return match - mData;
+}
+
+void AString::insert(const AString &from, size_t insertionPos) {
+    insert(from.c_str(), from.size(), insertionPos);
+}
+
+void AString::insert(const char *from, size_t size, size_t insertionPos) {
+    CHECK_GE(insertionPos, 0u);
+    CHECK_LE(insertionPos, mSize);
+
+    makeMutable();
+
+    if (mSize + size + 1 > mAllocSize) {
+        mAllocSize = (mAllocSize + size + 31) & -32;
+        mData = (char *)realloc(mData, mAllocSize);
+        CHECK(mData != NULL);
+    }
+
+    memmove(&mData[insertionPos + size],
+            &mData[insertionPos], mSize - insertionPos + 1);
+
+    memcpy(&mData[insertionPos], from, size);
+
+    mSize += size;
+}
+
+bool AString::operator<(const AString &other) const {
+    return compare(other) < 0;
+}
+
+bool AString::operator>(const AString &other) const {
+    return compare(other) > 0;
+}
+
+int AString::compare(const AString &other) const {
+    return strcmp(mData, other.mData);
+}
+
+void AString::tolower() {
+    makeMutable();
+
+    for (size_t i = 0; i < mSize; ++i) {
+        mData[i] = ::tolower(mData[i]);
+    }
+}
+
+bool AString::startsWith(const char *prefix) const {
+    return !strncmp(mData, prefix, strlen(prefix));
+}
+
+AString StringPrintf(const char *format, ...) {
+    va_list ap;
+    va_start(ap, format);
+
+    char *buffer;
+    vasprintf(&buffer, format, ap);
+
+    va_end(ap);
+
+    AString result(buffer);
+
+    free(buffer);
+    buffer = NULL;
+
+    return result;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
new file mode 100644
index 0000000..73047e7
--- /dev/null
+++ b/media/libstagefright/foundation/Android.mk
@@ -0,0 +1,35 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=               \
+    AAtomizer.cpp               \
+    ABuffer.cpp                 \
+    ADebug.cpp                  \
+    ALooper.cpp                 \
+    ALooperRoster.cpp           \
+    AMessage.cpp                \
+    AString.cpp                 \
+    base64.cpp                  \
+    hexdump.cpp
+
+LOCAL_C_INCLUDES:= \
+    frameworks/base/include/media/stagefright/foundation
+
+LOCAL_SHARED_LIBRARIES := \
+        libbinder         \
+        libmedia          \
+        libutils          \
+        libcutils         \
+        libui             \
+        libsonivox        \
+        libvorbisidec     \
+        libsurfaceflinger_client \
+        libcamera_client
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE:= libstagefright_foundation
+
+LOCAL_PRELINK_MODULE:= false
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
new file mode 100644
index 0000000..d5fb4e01
--- /dev/null
+++ b/media/libstagefright/foundation/base64.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#include "base64.h"
+
+#include "ABuffer.h"
+#include "ADebug.h"
+
+namespace android {
+
+sp<ABuffer> decodeBase64(const AString &s) {
+    if ((s.size() % 4) != 0) {
+        return NULL;
+    }
+
+    size_t n = s.size();
+    size_t padding = 0;
+    if (n >= 1 && s.c_str()[n - 1] == '=') {
+        padding = 1;
+
+        if (n >= 2 && s.c_str()[n - 2] == '=') {
+            padding = 2;
+        }
+    }
+
+    size_t outLen = 3 * s.size() / 4 - padding;
+
+    sp<ABuffer> buffer = new ABuffer(outLen);
+
+    uint8_t *out = buffer->data();
+    size_t j = 0;
+    uint32_t accum = 0;
+    for (size_t i = 0; i < n; ++i) {
+        char c = s.c_str()[i];
+        unsigned value;
+        if (c >= 'A' && c <= 'Z') {
+            value = c - 'A';
+        } else if (c >= 'a' && c <= 'z') {
+            value = 26 + c - 'a';
+        } else if (c >= '0' && c <= '9') {
+            value = 52 + c - '0';
+        } else if (c == '+') {
+            value = 62;
+        } else if (c == '/') {
+            value = 63;
+        } else if (c != '=') {
+            return NULL;
+        } else {
+            if (i < n - padding) {
+                return NULL;
+            }
+
+            value = 0;
+        }
+
+        accum = (accum << 6) | value;
+
+        if (((i + 1) % 4) == 0) {
+            out[j++] = (accum >> 16);
+
+            if (j < outLen) { out[j++] = (accum >> 8) & 0xff; } 
+            if (j < outLen) { out[j++] = accum & 0xff; }
+
+            accum = 0;
+        }
+    }
+
+    return buffer;
+}
+
+static char encode6Bit(unsigned x) {
+    if (x <= 25) {
+        return 'A' + x;
+    } else if (x <= 51) {
+        return 'a' + x - 26;
+    } else if (x <= 61) {
+        return '0' + x - 52;
+    } else if (x == 62) {
+        return '+';
+    } else {
+        return '/';
+    }
+}
+
+void encodeBase64(
+        const void *_data, size_t size, AString *out) {
+    out->clear();
+
+    const uint8_t *data = (const uint8_t *)_data;
+
+    size_t i;
+    for (i = 0; i < (size / 3) * 3; i += 3) {
+        uint8_t x1 = data[i];
+        uint8_t x2 = data[i + 1];
+        uint8_t x3 = data[i + 2];
+
+        out->append(encode6Bit(x1 >> 2));
+        out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
+        out->append(encode6Bit((x2 << 2 | x3 >> 6) & 0x3f));
+        out->append(encode6Bit(x3 & 0x3f));
+    }
+    switch (size % 3) {
+        case 0:
+            break;
+        case 2:
+        {
+            uint8_t x1 = data[i];
+            uint8_t x2 = data[i + 1];
+            out->append(encode6Bit(x1 >> 2));
+            out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
+            out->append(encode6Bit((x2 << 2) & 0x3f));
+            out->append('=');
+            break;
+        }
+        default:
+        {
+            uint8_t x1 = data[i];
+            out->append(encode6Bit(x1 >> 2));
+            out->append(encode6Bit((x1 << 4) & 0x3f));
+            out->append("==");
+            break;
+        }
+    }
+}
+
+}  // namespace android
diff --git a/media/libstagefright/foundation/hexdump.cpp b/media/libstagefright/foundation/hexdump.cpp
new file mode 100644
index 0000000..093b587
--- /dev/null
+++ b/media/libstagefright/foundation/hexdump.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#include "hexdump.h"
+
+#include "ADebug.h"
+#include "AString.h"
+
+#include <ctype.h>
+#include <stdint.h>
+#include <stdio.h>
+
+namespace android {
+
+void hexdump(const void *_data, size_t size) {
+    const uint8_t *data = (const uint8_t *)_data;
+
+    size_t offset = 0;
+    while (offset < size) {
+        AString line;
+
+        char tmp[32];
+        sprintf(tmp, "%08lx:  ", (unsigned long)offset);
+
+        line.append(tmp);
+
+        for (size_t i = 0; i < 16; ++i) {
+            if (i == 8) {
+                line.append(' ');
+            }
+            if (offset + i >= size) {
+                line.append("   ");
+            } else {
+                sprintf(tmp, "%02x ", data[offset + i]);
+                line.append(tmp);
+            }
+        }
+
+        line.append(' ');
+
+        for (size_t i = 0; i < 16; ++i) {
+            if (offset + i >= size) {
+                break;
+            }
+
+            if (isprint(data[offset + i])) {
+                line.append((char)data[offset + i]);
+            } else {
+                line.append('.');
+            }
+        }
+
+        LOG(INFO) << line;
+
+        offset += 16;
+    }
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
new file mode 100644
index 0000000..c96973b
--- /dev/null
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -0,0 +1,54 @@
+#ifndef MPEG2_TS_EXTRACTOR_H_
+
+#define MPEG2_TS_EXTRACTOR_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <utils/threads.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+struct AnotherPacketSource;
+struct ATSParser;
+struct DataSource;
+struct MPEG2TSSource;
+struct String8;
+
+struct MPEG2TSExtractor : public MediaExtractor {
+    MPEG2TSExtractor(const sp<DataSource> &source);
+
+    virtual size_t countTracks();
+    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
+
+    virtual sp<MetaData> getMetaData();
+
+    virtual uint32_t flags() const {
+        return CAN_PAUSE;
+    }
+
+private:
+    friend struct MPEG2TSSource;
+
+    Mutex mLock;
+
+    sp<DataSource> mDataSource;
+    sp<ATSParser> mParser;
+
+    Vector<sp<AnotherPacketSource> > mSourceImpls;
+
+    off_t mOffset;
+
+    void init();
+    status_t feedMore();
+
+    DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSExtractor);
+};
+
+bool SniffMPEG2TS(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence);
+
+}  // namespace android
+
+#endif  // MPEG2_TS_EXTRACTOR_H_
diff --git a/media/libstagefright/mpeg2ts/ABitReader.cpp b/media/libstagefright/mpeg2ts/ABitReader.cpp
new file mode 100644
index 0000000..24c8df8
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/ABitReader.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#include "ABitReader.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+ABitReader::ABitReader(const uint8_t *data, size_t size)
+    : mData(data),
+      mSize(size),
+      mReservoir(0),
+      mNumBitsLeft(0) {
+}
+
+void ABitReader::fillReservoir() {
+    CHECK_GT(mSize, 0u);
+
+    mReservoir = 0;
+    size_t i;
+    for (i = 0; mSize > 0 && i < 4; ++i) {
+        mReservoir = (mReservoir << 8) | *mData;
+
+        ++mData;
+        --mSize;
+    }
+
+    mNumBitsLeft = 8 * i;
+    mReservoir <<= 32 - mNumBitsLeft;
+}
+
+uint32_t ABitReader::getBits(size_t n) {
+    CHECK_LE(n, 32u);
+
+    uint32_t result = 0;
+    while (n > 0) {
+        if (mNumBitsLeft == 0) {
+            fillReservoir();
+        }
+
+        size_t m = n;
+        if (m > mNumBitsLeft) {
+            m = mNumBitsLeft;
+        }
+
+        result = (result << m) | (mReservoir >> (32 - m));
+        mReservoir <<= m;
+        mNumBitsLeft -= m;
+
+        n -= m;
+    }
+
+    return result;
+}
+
+void ABitReader::skipBits(size_t n) {
+    while (n > 32) {
+        getBits(32);
+        n -= 32;
+    }
+
+    if (n > 0) {
+        getBits(n);
+    }
+}
+
+void ABitReader::putBits(uint32_t x, size_t n) {
+    CHECK_LE(mNumBitsLeft + n, 32u);
+
+    mReservoir = (mReservoir >> n) | (x << (32 - n));
+    mNumBitsLeft += n;
+}
+
+size_t ABitReader::numBitsLeft() const {
+    return mSize * 8 + mNumBitsLeft;
+}
+
+const uint8_t *ABitReader::data() const {
+    CHECK_EQ(mNumBitsLeft % 8, 0u);
+
+    return mData - mNumBitsLeft / 8;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/mpeg2ts/ABitReader.h b/media/libstagefright/mpeg2ts/ABitReader.h
new file mode 100644
index 0000000..5135211
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/ABitReader.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef A_BIT_READER_H_
+
+#define A_BIT_READER_H_
+
+#include <media/stagefright/foundation/ABase.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+
+namespace android {
+
+struct ABitReader {
+    ABitReader(const uint8_t *data, size_t size);
+
+    uint32_t getBits(size_t n);
+    void skipBits(size_t n);
+
+    size_t numBitsLeft() const;
+
+    const uint8_t *data() const;
+
+private:
+    const uint8_t *mData;
+    size_t mSize;
+
+    uint32_t mReservoir;  // left-aligned bits
+    size_t mNumBitsLeft;
+
+    void fillReservoir();
+    void putBits(uint32_t x, size_t n);
+
+    DISALLOW_EVIL_CONSTRUCTORS(ABitReader);
+};
+
+}  // namespace android
+
+#endif  // A_BIT_READER_H_
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
new file mode 100644
index 0000000..d05975d
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -0,0 +1,941 @@
+/*
+ * 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.
+ */
+
+#include "ATSParser.h"
+
+#include "ABitReader.h"
+#include "AnotherPacketSource.h"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+static const size_t kTSPacketSize = 188;
+
+struct ATSParser::Program : public RefBase {
+    Program(unsigned programMapPID);
+
+    bool parsePID(
+            unsigned pid, unsigned payload_unit_start_indicator,
+            ABitReader *br);
+
+    sp<MediaSource> getSource(SourceType type);
+
+private:
+    unsigned mProgramMapPID;
+    KeyedVector<unsigned, sp<Stream> > mStreams;
+
+    void parseProgramMap(ABitReader *br);
+
+    DISALLOW_EVIL_CONSTRUCTORS(Program);
+};
+
+struct ATSParser::Stream : public RefBase {
+    Stream(unsigned elementaryPID, unsigned streamType);
+
+    void parse(
+            unsigned payload_unit_start_indicator,
+            ABitReader *br);
+
+    sp<MediaSource> getSource(SourceType type);
+
+protected:
+    virtual ~Stream();
+
+private:
+    unsigned mElementaryPID;
+    unsigned mStreamType;
+
+    sp<ABuffer> mBuffer;
+    sp<AnotherPacketSource> mSource;
+    bool mPayloadStarted;
+
+    void flush();
+    void parsePES(ABitReader *br);
+
+    void onPayloadData(
+            unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS,
+            const uint8_t *data, size_t size);
+
+    DISALLOW_EVIL_CONSTRUCTORS(Stream);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+ATSParser::Program::Program(unsigned programMapPID)
+    : mProgramMapPID(programMapPID) {
+}
+
+bool ATSParser::Program::parsePID(
+        unsigned pid, unsigned payload_unit_start_indicator,
+        ABitReader *br) {
+    if (pid == mProgramMapPID) {
+        if (payload_unit_start_indicator) {
+            unsigned skip = br->getBits(8);
+            br->skipBits(skip * 8);
+        }
+
+        parseProgramMap(br);
+        return true;
+    }
+
+    ssize_t index = mStreams.indexOfKey(pid);
+    if (index < 0) {
+        return false;
+    }
+
+    mStreams.editValueAt(index)->parse(
+            payload_unit_start_indicator, br);
+
+    return true;
+}
+
+void ATSParser::Program::parseProgramMap(ABitReader *br) {
+    unsigned table_id = br->getBits(8);
+    LOG(VERBOSE) << "  table_id = " << table_id;
+    CHECK_EQ(table_id, 0x02u);
+
+    unsigned section_syntax_indictor = br->getBits(1);
+    LOG(VERBOSE) << "  section_syntax_indictor = " << section_syntax_indictor;
+    CHECK_EQ(section_syntax_indictor, 1u);
+
+    CHECK_EQ(br->getBits(1), 0u);
+    LOG(VERBOSE) << "  reserved = " << br->getBits(2);
+
+    unsigned section_length = br->getBits(12);
+    LOG(VERBOSE) << "  section_length = " << section_length;
+    CHECK((section_length & 0xc00) == 0);
+    CHECK_LE(section_length, 1021u);
+
+    LOG(VERBOSE) << "  program_number = " << br->getBits(16);
+    LOG(VERBOSE) << "  reserved = " << br->getBits(2);
+    LOG(VERBOSE) << "  version_number = " << br->getBits(5);
+    LOG(VERBOSE) << "  current_next_indicator = " << br->getBits(1);
+    LOG(VERBOSE) << "  section_number = " << br->getBits(8);
+    LOG(VERBOSE) << "  last_section_number = " << br->getBits(8);
+    LOG(VERBOSE) << "  reserved = " << br->getBits(3);
+
+    LOG(VERBOSE) << "  PCR_PID = "
+              << StringPrintf("0x%04x", br->getBits(13));
+
+    LOG(VERBOSE) << "  reserved = " << br->getBits(4);
+
+    unsigned program_info_length = br->getBits(12);
+    LOG(VERBOSE) << "  program_info_length = " << program_info_length;
+    CHECK((program_info_length & 0xc00) == 0);
+
+    br->skipBits(program_info_length * 8);  // skip descriptors
+
+    // infoBytesRemaining is the number of bytes that make up the
+    // variable length section of ES_infos. It does not include the
+    // final CRC.
+    size_t infoBytesRemaining = section_length - 9 - program_info_length - 4;
+
+    while (infoBytesRemaining > 0) {
+        CHECK_GE(infoBytesRemaining, 5u);
+
+        unsigned streamType = br->getBits(8);
+        LOG(VERBOSE) << "    stream_type = "
+                  << StringPrintf("0x%02x", streamType);
+
+        LOG(VERBOSE) << "    reserved = " << br->getBits(3);
+
+        unsigned elementaryPID = br->getBits(13);
+        LOG(VERBOSE) << "    elementary_PID = "
+                  << StringPrintf("0x%04x", elementaryPID);
+
+        LOG(VERBOSE) << "    reserved = " << br->getBits(4);
+
+        unsigned ES_info_length = br->getBits(12);
+        LOG(VERBOSE) << "    ES_info_length = " << ES_info_length;
+        CHECK((ES_info_length & 0xc00) == 0);
+
+        CHECK_GE(infoBytesRemaining - 5, ES_info_length);
+
+#if 0
+        br->skipBits(ES_info_length * 8);  // skip descriptors
+#else
+        unsigned info_bytes_remaining = ES_info_length;
+        while (info_bytes_remaining >= 2) {
+            LOG(VERBOSE) << "      tag = " << StringPrintf("0x%02x", br->getBits(8));
+
+            unsigned descLength = br->getBits(8);
+            LOG(VERBOSE) << "      len = " << descLength;
+
+            CHECK_GE(info_bytes_remaining, 2 + descLength);
+
+            br->skipBits(descLength * 8);
+
+            info_bytes_remaining -= descLength + 2;
+        }
+        CHECK_EQ(info_bytes_remaining, 0u);
+#endif
+
+        ssize_t index = mStreams.indexOfKey(elementaryPID);
+#if 0  // XXX revisit
+        CHECK_LT(index, 0);
+        mStreams.add(elementaryPID, new Stream(elementaryPID, streamType));
+#else
+        if (index < 0) {
+            mStreams.add(elementaryPID, new Stream(elementaryPID, streamType));
+        }
+#endif
+
+        infoBytesRemaining -= 5 + ES_info_length;
+    }
+
+    CHECK_EQ(infoBytesRemaining, 0u);
+
+    LOG(VERBOSE) << "  CRC = " << StringPrintf("0x%08x", br->getBits(32));
+}
+
+sp<MediaSource> ATSParser::Program::getSource(SourceType type) {
+    for (size_t i = 0; i < mStreams.size(); ++i) {
+        sp<MediaSource> source = mStreams.editValueAt(i)->getSource(type);
+        if (source != NULL) {
+            return source;
+        }
+    }
+
+    return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+ATSParser::Stream::Stream(unsigned elementaryPID, unsigned streamType)
+    : mElementaryPID(elementaryPID),
+      mStreamType(streamType),
+      mBuffer(new ABuffer(65536)),
+      mPayloadStarted(false) {
+    mBuffer->setRange(0, 0);
+}
+
+ATSParser::Stream::~Stream() {
+}
+
+void ATSParser::Stream::parse(
+        unsigned payload_unit_start_indicator, ABitReader *br) {
+    if (payload_unit_start_indicator) {
+        if (mPayloadStarted) {
+            // Otherwise we run the danger of receiving the trailing bytes
+            // of a PES packet that we never saw the start of and assuming
+            // we have a a complete PES packet.
+
+            flush();
+        }
+
+        mPayloadStarted = true;
+    }
+
+    if (!mPayloadStarted) {
+        return;
+    }
+
+    size_t payloadSizeBits = br->numBitsLeft();
+    CHECK_EQ(payloadSizeBits % 8, 0u);
+
+    CHECK_LE(mBuffer->size() + payloadSizeBits / 8, mBuffer->capacity());
+
+    memcpy(mBuffer->data() + mBuffer->size(), br->data(), payloadSizeBits / 8);
+    mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8);
+}
+
+void ATSParser::Stream::parsePES(ABitReader *br) {
+    unsigned packet_startcode_prefix = br->getBits(24);
+
+    LOG(VERBOSE) << "packet_startcode_prefix = "
+              << StringPrintf("0x%08x", packet_startcode_prefix);
+
+    CHECK_EQ(packet_startcode_prefix, 0x000001u);
+
+    unsigned stream_id = br->getBits(8);
+    LOG(VERBOSE) << "stream_id = " << StringPrintf("0x%02x", stream_id);
+
+    unsigned PES_packet_length = br->getBits(16);
+    LOG(VERBOSE) << "PES_packet_length = " << PES_packet_length;
+
+    if (stream_id != 0xbc  // program_stream_map
+            && stream_id != 0xbe  // padding_stream
+            && stream_id != 0xbf  // private_stream_2
+            && stream_id != 0xf0  // ECM
+            && stream_id != 0xf1  // EMM
+            && stream_id != 0xff  // program_stream_directory
+            && stream_id != 0xf2  // DSMCC
+            && stream_id != 0xf8) {  // H.222.1 type E
+        CHECK_EQ(br->getBits(2), 2u);
+
+        LOG(VERBOSE) << "PES_scrambling_control = " << br->getBits(2);
+        LOG(VERBOSE) << "PES_priority = " << br->getBits(1);
+        LOG(VERBOSE) << "data_alignment_indicator = " << br->getBits(1);
+        LOG(VERBOSE) << "copyright = " << br->getBits(1);
+        LOG(VERBOSE) << "original_or_copy = " << br->getBits(1);
+
+        unsigned PTS_DTS_flags = br->getBits(2);
+        LOG(VERBOSE) << "PTS_DTS_flags = " << PTS_DTS_flags;
+
+        unsigned ESCR_flag = br->getBits(1);
+        LOG(VERBOSE) << "ESCR_flag = " << ESCR_flag;
+
+        unsigned ES_rate_flag = br->getBits(1);
+        LOG(VERBOSE) << "ES_rate_flag = " << ES_rate_flag;
+
+        unsigned DSM_trick_mode_flag = br->getBits(1);
+        LOG(VERBOSE) << "DSM_trick_mode_flag = " << DSM_trick_mode_flag;
+
+        unsigned additional_copy_info_flag = br->getBits(1);
+        LOG(VERBOSE) << "additional_copy_info_flag = "
+                  << additional_copy_info_flag;
+
+        LOG(VERBOSE) << "PES_CRC_flag = " << br->getBits(1);
+        LOG(VERBOSE) << "PES_extension_flag = " << br->getBits(1);
+
+        unsigned PES_header_data_length = br->getBits(8);
+        LOG(VERBOSE) << "PES_header_data_length = " << PES_header_data_length;
+
+        unsigned optional_bytes_remaining = PES_header_data_length;
+
+        uint64_t PTS = 0, DTS = 0;
+
+        if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) {
+            CHECK_GE(optional_bytes_remaining, 5u);
+
+            CHECK_EQ(br->getBits(4), PTS_DTS_flags);
+
+            PTS = ((uint64_t)br->getBits(3)) << 30;
+            CHECK_EQ(br->getBits(1), 1u);
+            PTS |= ((uint64_t)br->getBits(15)) << 15;
+            CHECK_EQ(br->getBits(1), 1u);
+            PTS |= br->getBits(15);
+            CHECK_EQ(br->getBits(1), 1u);
+
+            LOG(VERBOSE) << "PTS = " << PTS;
+            // LOG(INFO) << "PTS = " << PTS / 90000.0f << " secs";
+
+            optional_bytes_remaining -= 5;
+
+            if (PTS_DTS_flags == 3) {
+                CHECK_GE(optional_bytes_remaining, 5u);
+
+                CHECK_EQ(br->getBits(4), 1u);
+
+                DTS = ((uint64_t)br->getBits(3)) << 30;
+                CHECK_EQ(br->getBits(1), 1u);
+                DTS |= ((uint64_t)br->getBits(15)) << 15;
+                CHECK_EQ(br->getBits(1), 1u);
+                DTS |= br->getBits(15);
+                CHECK_EQ(br->getBits(1), 1u);
+
+                LOG(VERBOSE) << "DTS = " << DTS;
+
+                optional_bytes_remaining -= 5;
+            }
+        }
+
+        if (ESCR_flag) {
+            CHECK_GE(optional_bytes_remaining, 6u);
+
+            br->getBits(2);
+
+            uint64_t ESCR = ((uint64_t)br->getBits(3)) << 30;
+            CHECK_EQ(br->getBits(1), 1u);
+            ESCR |= ((uint64_t)br->getBits(15)) << 15;
+            CHECK_EQ(br->getBits(1), 1u);
+            ESCR |= br->getBits(15);
+            CHECK_EQ(br->getBits(1), 1u);
+
+            LOG(VERBOSE) << "ESCR = " << ESCR;
+            LOG(VERBOSE) << "ESCR_extension = " << br->getBits(9);
+
+            CHECK_EQ(br->getBits(1), 1u);
+
+            optional_bytes_remaining -= 6;
+        }
+
+        if (ES_rate_flag) {
+            CHECK_GE(optional_bytes_remaining, 3u);
+
+            CHECK_EQ(br->getBits(1), 1u);
+            LOG(VERBOSE) << "ES_rate = " << br->getBits(22);
+            CHECK_EQ(br->getBits(1), 1u);
+
+            optional_bytes_remaining -= 3;
+        }
+
+        br->skipBits(optional_bytes_remaining * 8);
+
+        // ES data follows.
+
+        onPayloadData(
+                PTS_DTS_flags, PTS, DTS,
+                br->data(), br->numBitsLeft() / 8);
+
+        if (PES_packet_length != 0) {
+            CHECK_GE(PES_packet_length, PES_header_data_length + 3);
+
+            unsigned dataLength =
+                PES_packet_length - 3 - PES_header_data_length;
+
+            CHECK_EQ(br->numBitsLeft(), dataLength * 8);
+
+            br->skipBits(dataLength * 8);
+        } else {
+            size_t payloadSizeBits = br->numBitsLeft();
+            CHECK((payloadSizeBits % 8) == 0);
+
+            LOG(VERBOSE) << "There's " << (payloadSizeBits / 8)
+                         << " bytes of payload.";
+        }
+    } else if (stream_id == 0xbe) {  // padding_stream
+        CHECK_NE(PES_packet_length, 0u);
+        br->skipBits(PES_packet_length * 8);
+    } else {
+        CHECK_NE(PES_packet_length, 0u);
+        br->skipBits(PES_packet_length * 8);
+    }
+}
+
+void ATSParser::Stream::flush() {
+    if (mBuffer->size() == 0) {
+        return;
+    }
+
+    LOG(VERBOSE) << "flushing stream "
+                 << StringPrintf("0x%04x", mElementaryPID)
+                 << " size = " << mBuffer->size();
+
+    ABitReader br(mBuffer->data(), mBuffer->size());
+    parsePES(&br);
+
+    mBuffer->setRange(0, 0);
+}
+
+static sp<ABuffer> FindNAL(
+        const uint8_t *data, size_t size, unsigned nalType,
+        size_t *stopOffset) {
+    bool foundStart = false;
+    size_t startOffset = 0;
+
+    size_t offset = 0;
+    for (;;) {
+        while (offset + 3 < size
+                && memcmp("\x00\x00\x00\x01", &data[offset], 4)) {
+            ++offset;
+        }
+
+        if (foundStart) {
+            size_t nalSize;
+            if (offset + 3 >= size) {
+                nalSize = size - startOffset;
+            } else {
+                nalSize = offset - startOffset;
+            }
+
+            sp<ABuffer> nal = new ABuffer(nalSize);
+            memcpy(nal->data(), &data[startOffset], nalSize);
+
+            if (stopOffset != NULL) {
+                *stopOffset = startOffset + nalSize;
+            }
+
+            return nal;
+        }
+
+        if (offset + 4 >= size) {
+            return NULL;
+        }
+
+        if ((data[offset + 4] & 0x1f) == nalType) {
+            foundStart = true;
+            startOffset = offset + 4;
+        }
+
+        offset += 4;
+    }
+}
+
+static unsigned parseUE(ABitReader *br) {
+    unsigned numZeroes = 0;
+    while (br->getBits(1) == 0) {
+        ++numZeroes;
+    }
+
+    unsigned x = br->getBits(numZeroes);
+
+    return x + (1u << numZeroes) - 1;
+}
+
+// Determine video dimensions from the sequence parameterset.
+static void FindDimensions(
+        const sp<ABuffer> seqParamSet, int32_t *width, int32_t *height) {
+    ABitReader br(seqParamSet->data() + 1, seqParamSet->size() - 1);
+
+    unsigned profile_idc = br.getBits(8);
+    br.skipBits(16);
+    parseUE(&br);  // seq_parameter_set_id
+
+    if (profile_idc == 100 || profile_idc == 110
+            || profile_idc == 122 || profile_idc == 144) {
+        TRESPASS();
+    }
+
+    parseUE(&br);  // log2_max_frame_num_minus4
+    unsigned pic_order_cnt_type = parseUE(&br);
+
+    if (pic_order_cnt_type == 0) {
+        parseUE(&br);  // log2_max_pic_order_cnt_lsb_minus4
+    } else if (pic_order_cnt_type == 1) {
+        br.getBits(1);  // delta_pic_order_always_zero_flag
+        parseUE(&br);  // offset_for_non_ref_pic
+        parseUE(&br);  // offset_for_top_to_bottom_field
+
+        unsigned num_ref_frames_in_pic_order_cnt_cycle = parseUE(&br);
+        for (unsigned i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) {
+            parseUE(&br);  // offset_for_ref_frame
+        }
+    }
+
+    parseUE(&br);  // num_ref_frames
+    br.getBits(1);  // gaps_in_frame_num_value_allowed_flag
+
+    unsigned pic_width_in_mbs_minus1 = parseUE(&br);
+    unsigned pic_height_in_map_units_minus1 = parseUE(&br);
+    unsigned frame_mbs_only_flag = br.getBits(1);
+
+    *width = pic_width_in_mbs_minus1 * 16 + 16;
+
+    *height = (2 - frame_mbs_only_flag)
+        * (pic_height_in_map_units_minus1 * 16 + 16);
+}
+
+static sp<ABuffer> MakeAVCCodecSpecificData(
+        const sp<ABuffer> &buffer, int32_t *width, int32_t *height) {
+    const uint8_t *data = buffer->data();
+    size_t size = buffer->size();
+
+    sp<ABuffer> seqParamSet = FindNAL(data, size, 7, NULL);
+    if (seqParamSet == NULL) {
+        return NULL;
+    }
+
+    FindDimensions(seqParamSet, width, height);
+
+    size_t stopOffset;
+    sp<ABuffer> picParamSet = FindNAL(data, size, 8, &stopOffset);
+    CHECK(picParamSet != NULL);
+
+    buffer->setRange(stopOffset, size - stopOffset);
+    LOG(INFO) << "buffer has " << buffer->size() << " bytes left.";
+
+    size_t csdSize =
+        1 + 3 + 1 + 1
+        + 2 * 1 + seqParamSet->size()
+        + 1 + 2 * 1 + picParamSet->size();
+
+    sp<ABuffer> csd = new ABuffer(csdSize);
+    uint8_t *out = csd->data();
+
+    *out++ = 0x01;  // configurationVersion
+    memcpy(out, seqParamSet->data() + 1, 3);  // profile/level...
+    out += 3;
+    *out++ = (0x3f << 2) | 1;  // lengthSize == 2 bytes
+    *out++ = 0xe0 | 1;
+
+    *out++ = seqParamSet->size() >> 8;
+    *out++ = seqParamSet->size() & 0xff;
+    memcpy(out, seqParamSet->data(), seqParamSet->size());
+    out += seqParamSet->size();
+
+    *out++ = 1;
+
+    *out++ = picParamSet->size() >> 8;
+    *out++ = picParamSet->size() & 0xff;
+    memcpy(out, picParamSet->data(), picParamSet->size());
+
+    return csd;
+}
+
+static bool getNextNALUnit(
+        const uint8_t **_data, size_t *_size,
+        const uint8_t **nalStart, size_t *nalSize) {
+    const uint8_t *data = *_data;
+    size_t size = *_size;
+
+    *nalStart = NULL;
+    *nalSize = 0;
+
+    if (size == 0) {
+        return false;
+    }
+
+    size_t offset = 0;
+    for (;;) {
+        CHECK_LT(offset + 2, size);
+
+        if (!memcmp("\x00\x00\x01", &data[offset], 3)) {
+            break;
+        }
+
+        CHECK_EQ((unsigned)data[offset], 0x00u);
+        ++offset;
+    }
+
+    offset += 3;
+    size_t startOffset = offset;
+
+    while (offset + 2 < size
+            && memcmp("\x00\x00\x00", &data[offset], 3)
+            && memcmp("\x00\x00\x01", &data[offset], 3)) {
+        ++offset;
+    }
+
+    if (offset + 2 >= size) {
+        *nalStart = &data[startOffset];
+        *nalSize = size - startOffset;
+
+        *_data = NULL;
+        *_size = 0;
+
+        return true;
+    }
+
+    size_t endOffset = offset;
+
+    while (offset + 2 < size && memcmp("\x00\x00\x01", &data[offset], 3)) {
+        CHECK_EQ((unsigned)data[offset], 0x00u);
+        ++offset;
+    }
+
+    CHECK_LT(offset + 2, size);
+
+    *nalStart = &data[startOffset];
+    *nalSize = endOffset - startOffset;
+
+    *_data = &data[offset];
+    *_size = size - offset;
+
+    return true;
+}
+
+sp<ABuffer> MakeCleanAVCData(const uint8_t *data, size_t size) {
+    const uint8_t *tmpData = data;
+    size_t tmpSize = size;
+
+    size_t totalSize = 0;
+    const uint8_t *nalStart;
+    size_t nalSize;
+    while (getNextNALUnit(&tmpData, &tmpSize, &nalStart, &nalSize)) {
+        totalSize += 4 + nalSize;
+    }
+
+    sp<ABuffer> buffer = new ABuffer(totalSize);
+    size_t offset = 0;
+    while (getNextNALUnit(&data, &size, &nalStart, &nalSize)) {
+        memcpy(buffer->data() + offset, "\x00\x00\x00\x01", 4);
+        memcpy(buffer->data() + offset + 4, nalStart, nalSize);
+
+        offset += 4 + nalSize;
+    }
+
+    return buffer;
+}
+
+static sp<ABuffer> FindMPEG2ADTSConfig(
+        const sp<ABuffer> &buffer, int32_t *sampleRate, int32_t *channelCount) {
+    ABitReader br(buffer->data(), buffer->size());
+
+    CHECK_EQ(br.getBits(12), 0xfffu);
+    CHECK_EQ(br.getBits(1), 0u);
+    CHECK_EQ(br.getBits(2), 0u);
+    br.getBits(1);  // protection_absent
+    unsigned profile = br.getBits(2);
+    LOG(INFO) << "profile = " << profile;
+    CHECK_NE(profile, 3u);
+    unsigned sampling_freq_index = br.getBits(4);
+    br.getBits(1);  // private_bit
+    unsigned channel_configuration = br.getBits(3);
+    CHECK_NE(channel_configuration, 0u);
+
+    LOG(INFO) << "sampling_freq_index = " << sampling_freq_index;
+    LOG(INFO) << "channel_configuration = " << channel_configuration;
+
+    CHECK_LE(sampling_freq_index, 11u);
+    static const int32_t kSamplingFreq[] = {
+        96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+        16000, 12000, 11025, 8000
+    };
+    *sampleRate = kSamplingFreq[sampling_freq_index];
+
+    *channelCount = channel_configuration;
+
+    static const uint8_t kStaticESDS[] = {
+        0x03, 22,
+        0x00, 0x00,     // ES_ID
+        0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
+
+        0x04, 17,
+        0x40,                       // Audio ISO/IEC 14496-3
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+
+        0x05, 2,
+        // AudioSpecificInfo follows
+
+        // oooo offf fccc c000
+        // o - audioObjectType
+        // f - samplingFreqIndex
+        // c - channelConfig
+    };
+    sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + 2);
+    memcpy(csd->data(), kStaticESDS, sizeof(kStaticESDS));
+
+    csd->data()[sizeof(kStaticESDS)] =
+        ((profile + 1) << 3) | (sampling_freq_index >> 1);
+
+    csd->data()[sizeof(kStaticESDS) + 1] =
+        ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
+
+    hexdump(csd->data(), csd->size());
+    return csd;
+}
+
+void ATSParser::Stream::onPayloadData(
+        unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS,
+        const uint8_t *data, size_t size) {
+    LOG(VERBOSE) << "onPayloadData mStreamType="
+                 << StringPrintf("0x%02x", mStreamType);
+
+    sp<ABuffer> buffer;
+
+    if (mStreamType == 0x1b) {
+        buffer = MakeCleanAVCData(data, size);
+    } else {
+        // hexdump(data, size);
+
+        buffer = new ABuffer(size);
+        memcpy(buffer->data(), data, size);
+    }
+
+    if (mSource == NULL) {
+        sp<MetaData> meta = new MetaData;
+
+        if (mStreamType == 0x1b) {
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+
+            int32_t width, height;
+            sp<ABuffer> csd = MakeAVCCodecSpecificData(buffer, &width, &height);
+
+            if (csd == NULL) {
+                return;
+            }
+
+            meta->setData(kKeyAVCC, 0, csd->data(), csd->size());
+            meta->setInt32(kKeyWidth, width);
+            meta->setInt32(kKeyHeight, height);
+        } else {
+            CHECK_EQ(mStreamType, 0x0fu);
+
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+
+            int32_t sampleRate, channelCount;
+            sp<ABuffer> csd =
+                FindMPEG2ADTSConfig(buffer, &sampleRate, &channelCount);
+
+            LOG(INFO) << "sampleRate = " << sampleRate;
+            LOG(INFO) << "channelCount = " << channelCount;
+
+            meta->setInt32(kKeySampleRate, sampleRate);
+            meta->setInt32(kKeyChannelCount, channelCount);
+
+            meta->setData(kKeyESDS, 0, csd->data(), csd->size());
+        }
+
+        LOG(INFO) << "created source!";
+        mSource = new AnotherPacketSource(meta);
+
+        // fall through
+    }
+
+    CHECK(PTS_DTS_flags == 2 || PTS_DTS_flags == 3);
+    buffer->meta()->setInt64("time", (PTS * 100) / 9);
+
+    if (mStreamType == 0x0f) {
+        // WHY???
+        buffer->setRange(7, buffer->size() - 7);
+    }
+
+    mSource->queueAccessUnit(buffer);
+}
+
+sp<MediaSource> ATSParser::Stream::getSource(SourceType type) {
+    if ((type == AVC_VIDEO && mStreamType == 0x1b)
+        || (type == MPEG2ADTS_AUDIO && mStreamType == 0x0f)) {
+        return mSource;
+    }
+
+    return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+ATSParser::ATSParser() {
+}
+
+ATSParser::~ATSParser() {
+}
+
+void ATSParser::feedTSPacket(const void *data, size_t size) {
+    CHECK_EQ(size, kTSPacketSize);
+
+    ABitReader br((const uint8_t *)data, kTSPacketSize);
+    parseTS(&br);
+}
+
+void ATSParser::parseProgramAssociationTable(ABitReader *br) {
+    unsigned table_id = br->getBits(8);
+    LOG(VERBOSE) << "  table_id = " << table_id;
+    CHECK_EQ(table_id, 0x00u);
+
+    unsigned section_syntax_indictor = br->getBits(1);
+    LOG(VERBOSE) << "  section_syntax_indictor = " << section_syntax_indictor;
+    CHECK_EQ(section_syntax_indictor, 1u);
+
+    CHECK_EQ(br->getBits(1), 0u);
+    LOG(VERBOSE) << "  reserved = " << br->getBits(2);
+
+    unsigned section_length = br->getBits(12);
+    LOG(VERBOSE) << "  section_length = " << section_length;
+    CHECK((section_length & 0xc00) == 0);
+
+    LOG(VERBOSE) << "  transport_stream_id = " << br->getBits(16);
+    LOG(VERBOSE) << "  reserved = " << br->getBits(2);
+    LOG(VERBOSE) << "  version_number = " << br->getBits(5);
+    LOG(VERBOSE) << "  current_next_indicator = " << br->getBits(1);
+    LOG(VERBOSE) << "  section_number = " << br->getBits(8);
+    LOG(VERBOSE) << "  last_section_number = " << br->getBits(8);
+
+    size_t numProgramBytes = (section_length - 5 /* header */ - 4 /* crc */);
+    CHECK_EQ((numProgramBytes % 4), 0u);
+
+    for (size_t i = 0; i < numProgramBytes / 4; ++i) {
+        unsigned program_number = br->getBits(16);
+        LOG(VERBOSE) << "    program_number = " << program_number;
+
+        LOG(VERBOSE) << "    reserved = " << br->getBits(3);
+
+        if (program_number == 0) {
+            LOG(VERBOSE) << "    network_PID = "
+                      << StringPrintf("0x%04x", br->getBits(13));
+        } else {
+            unsigned programMapPID = br->getBits(13);
+
+            LOG(VERBOSE) << "    program_map_PID = "
+                      << StringPrintf("0x%04x", programMapPID);
+
+            mPrograms.push(new Program(programMapPID));
+        }
+    }
+
+    LOG(VERBOSE) << "  CRC = " << StringPrintf("0x%08x", br->getBits(32));
+}
+
+void ATSParser::parsePID(
+        ABitReader *br, unsigned PID,
+        unsigned payload_unit_start_indicator) {
+    if (PID == 0) {
+        if (payload_unit_start_indicator) {
+            unsigned skip = br->getBits(8);
+            br->skipBits(skip * 8);
+        }
+        parseProgramAssociationTable(br);
+        return;
+    }
+
+    bool handled = false;
+    for (size_t i = 0; i < mPrograms.size(); ++i) {
+        if (mPrograms.editItemAt(i)->parsePID(
+                    PID, payload_unit_start_indicator, br)) {
+            handled = true;
+            break;
+        }
+    }
+
+    if (!handled) {
+        LOG(WARNING) << "PID " << StringPrintf("0x%04x", PID)
+                     << " not handled.";
+    }
+}
+
+void ATSParser::parseAdaptationField(ABitReader *br) {
+    unsigned adaptation_field_length = br->getBits(8);
+    if (adaptation_field_length > 0) {
+        br->skipBits(adaptation_field_length * 8);  // XXX
+    }
+}
+
+void ATSParser::parseTS(ABitReader *br) {
+    LOG(VERBOSE) << "---";
+
+    unsigned sync_byte = br->getBits(8);
+    CHECK_EQ(sync_byte, 0x47u);
+
+    LOG(VERBOSE) << "transport_error_indicator = " << br->getBits(1);
+
+    unsigned payload_unit_start_indicator = br->getBits(1);
+    LOG(VERBOSE) << "payload_unit_start_indicator = "
+                 << payload_unit_start_indicator;
+
+    LOG(VERBOSE) << "transport_priority = " << br->getBits(1);
+
+    unsigned PID = br->getBits(13);
+    LOG(VERBOSE) << "PID = " << StringPrintf("0x%04x", PID);
+
+    LOG(VERBOSE) << "transport_scrambling_control = " << br->getBits(2);
+
+    unsigned adaptation_field_control = br->getBits(2);
+    LOG(VERBOSE) << "adaptation_field_control = " << adaptation_field_control;
+
+    LOG(VERBOSE) << "continuity_counter = " << br->getBits(4);
+
+    if (adaptation_field_control == 2 || adaptation_field_control == 3) {
+        parseAdaptationField(br);
+    }
+
+    if (adaptation_field_control == 1 || adaptation_field_control == 3) {
+        parsePID(br, PID, payload_unit_start_indicator);
+    }
+}
+
+sp<MediaSource> ATSParser::getSource(SourceType type) {
+    for (size_t i = 0; i < mPrograms.size(); ++i) {
+        sp<MediaSource> source = mPrograms.editItemAt(i)->getSource(type);
+
+        if (source != NULL) {
+            return source;
+        }
+    }
+
+    return NULL;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
new file mode 100644
index 0000000..1e22e7b
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#ifndef A_TS_PARSER_H_
+
+#define A_TS_PARSER_H_
+
+#include <sys/types.h>
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct ABitReader;
+struct MediaSource;
+
+struct ATSParser : public RefBase {
+    ATSParser();
+
+    void feedTSPacket(const void *data, size_t size);
+
+    enum SourceType {
+        AVC_VIDEO,
+        MPEG2ADTS_AUDIO
+    };
+    sp<MediaSource> getSource(SourceType type);
+
+protected:
+    virtual ~ATSParser();
+
+private:
+    struct Program;
+    struct Stream;
+
+    Vector<sp<Program> > mPrograms;
+
+    void parseProgramAssociationTable(ABitReader *br);
+    void parseProgramMap(ABitReader *br);
+    void parsePES(ABitReader *br);
+
+    void parsePID(
+        ABitReader *br, unsigned PID,
+        unsigned payload_unit_start_indicator);
+
+    void parseAdaptationField(ABitReader *br);
+    void parseTS(ABitReader *br);
+
+    DISALLOW_EVIL_CONSTRUCTORS(ATSParser);
+};
+
+}  // namespace android
+
+#endif  // A_TS_PARSER_H_
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
new file mode 100644
index 0000000..b6772eb
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=                 \
+        ABitReader.cpp            \
+        AnotherPacketSource.cpp   \
+        ATSParser.cpp             \
+        MPEG2TSExtractor.cpp      \
+
+LOCAL_C_INCLUDES:= \
+	$(JNI_H_INCLUDE) \
+	$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+        $(TOP)/frameworks/base/media/libstagefright
+
+LOCAL_MODULE:= libstagefright_mpeg2ts
+
+ifeq ($(TARGET_ARCH),arm)
+    LOCAL_CFLAGS += -Wno-psabi
+endif
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
new file mode 100644
index 0000000..3d51177
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#include "AnotherPacketSource.h"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+AnotherPacketSource::AnotherPacketSource(const sp<MetaData> &meta)
+    : mFormat(meta),
+      mEOSResult(OK) {
+}
+
+AnotherPacketSource::~AnotherPacketSource() {
+}
+
+status_t AnotherPacketSource::start(MetaData *params) {
+    return OK;
+}
+
+status_t AnotherPacketSource::stop() {
+    return OK;
+}
+
+sp<MetaData> AnotherPacketSource::getFormat() {
+    return mFormat;
+}
+
+status_t AnotherPacketSource::read(
+        MediaBuffer **out, const ReadOptions *) {
+    *out = NULL;
+
+    Mutex::Autolock autoLock(mLock);
+    while (mEOSResult == OK && mBuffers.empty()) {
+        mCondition.wait(mLock);
+    }
+
+    if (!mBuffers.empty()) {
+        const sp<ABuffer> buffer = *mBuffers.begin();
+
+        uint64_t timeUs;
+        CHECK(buffer->meta()->findInt64(
+                    "time", (int64_t *)&timeUs));
+
+        MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
+        mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
+
+        // hexdump(buffer->data(), buffer->size());
+
+        memcpy(mediaBuffer->data(), buffer->data(), buffer->size());
+        *out = mediaBuffer;
+
+        mBuffers.erase(mBuffers.begin());
+        return OK;
+    }
+
+    return mEOSResult;
+}
+
+void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
+    int32_t damaged;
+    if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
+        // LOG(VERBOSE) << "discarding damaged AU";
+        return;
+    }
+
+    Mutex::Autolock autoLock(mLock);
+    mBuffers.push_back(buffer);
+    mCondition.signal();
+}
+
+void AnotherPacketSource::signalEOS(status_t result) {
+    CHECK(result != OK);
+
+    Mutex::Autolock autoLock(mLock);
+    mEOSResult = result;
+    mCondition.signal();
+}
+
+bool AnotherPacketSource::hasBufferAvailable(status_t *finalResult) {
+    Mutex::Autolock autoLock(mLock);
+    if (!mBuffers.empty()) {
+        return true;
+    }
+
+    *finalResult = mEOSResult;
+    return false;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
new file mode 100644
index 0000000..ce83d21
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifndef ANOTHER_PACKET_SOURCE_H_
+
+#define ANOTHER_PACKET_SOURCE_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+
+namespace android {
+
+struct ABuffer;
+
+struct AnotherPacketSource : public MediaSource {
+    AnotherPacketSource(const sp<MetaData> &meta);
+
+    virtual status_t start(MetaData *params = NULL);
+    virtual status_t stop();
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+    bool hasBufferAvailable(status_t *finalResult);
+
+    void queueAccessUnit(const sp<ABuffer> &buffer);
+    void signalEOS(status_t result);
+
+protected:
+    virtual ~AnotherPacketSource();
+
+private:
+    Mutex mLock;
+    Condition mCondition;
+
+    sp<MetaData> mFormat;
+    List<sp<ABuffer> > mBuffers;
+    status_t mEOSResult;
+
+    DISALLOW_EVIL_CONSTRUCTORS(AnotherPacketSource);
+};
+
+
+}  // namespace android
+
+#endif  // ANOTHER_PACKET_SOURCE_H_
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
new file mode 100644
index 0000000..b798273
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MPEG2TSExtractor"
+#include <utils/Log.h>
+
+#include "include/MPEG2TSExtractor.h"
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/String8.h>
+
+#include "AnotherPacketSource.h"
+#include "ATSParser.h"
+
+namespace android {
+
+struct MPEG2TSSource : public MediaSource {
+    MPEG2TSSource(
+            const sp<MPEG2TSExtractor> &extractor,
+            const sp<AnotherPacketSource> &impl);
+
+    virtual status_t start(MetaData *params = NULL);
+    virtual status_t stop();
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+private:
+    sp<MPEG2TSExtractor> mExtractor;
+    sp<AnotherPacketSource> mImpl;
+
+    DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSSource);
+};
+
+MPEG2TSSource::MPEG2TSSource(
+        const sp<MPEG2TSExtractor> &extractor,
+        const sp<AnotherPacketSource> &impl)
+    : mExtractor(extractor),
+      mImpl(impl) {
+}
+
+status_t MPEG2TSSource::start(MetaData *params) {
+    return mImpl->start(params);
+}
+
+status_t MPEG2TSSource::stop() {
+    return mImpl->stop();
+}
+
+sp<MetaData> MPEG2TSSource::getFormat() {
+    return mImpl->getFormat();
+}
+
+status_t MPEG2TSSource::read(
+        MediaBuffer **out, const ReadOptions *options) {
+    *out = NULL;
+
+    status_t finalResult;
+    while (!mImpl->hasBufferAvailable(&finalResult)) {
+        if (finalResult != OK) {
+            return ERROR_END_OF_STREAM;
+        }
+
+        status_t err = mExtractor->feedMore();
+        if (err != OK) {
+            mImpl->signalEOS(err);
+        }
+    }
+
+    return mImpl->read(out, options);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG2TSExtractor::MPEG2TSExtractor(const sp<DataSource> &source)
+    : mDataSource(source),
+      mParser(new ATSParser),
+      mOffset(0) {
+    init();
+}
+
+size_t MPEG2TSExtractor::countTracks() {
+    return mSourceImpls.size();
+}
+
+sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) {
+    if (index >= mSourceImpls.size()) {
+        return NULL;
+    }
+
+    return new MPEG2TSSource(this, mSourceImpls.editItemAt(index));
+}
+
+sp<MetaData> MPEG2TSExtractor::getTrackMetaData(
+        size_t index, uint32_t flags) {
+    return index < mSourceImpls.size()
+        ? mSourceImpls.editItemAt(index)->getFormat() : NULL;
+}
+
+sp<MetaData> MPEG2TSExtractor::getMetaData() {
+    sp<MetaData> meta = new MetaData;
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
+
+    return meta;
+}
+
+void MPEG2TSExtractor::init() {
+    bool haveAudio = false;
+    bool haveVideo = false;
+
+    while (feedMore() == OK) {
+        ATSParser::SourceType type;
+        if (haveAudio && haveVideo) {
+            break;
+        }
+        if (haveVideo) {
+            type = ATSParser::MPEG2ADTS_AUDIO;
+        } else {
+            type = ATSParser::AVC_VIDEO;
+        }
+        sp<AnotherPacketSource> impl =
+            (AnotherPacketSource *)mParser->getSource(type).get();
+
+        if (impl != NULL) {
+            if (type == ATSParser::MPEG2ADTS_AUDIO) {
+                haveAudio = true;
+            } else {
+                haveVideo = true;
+            }
+            mSourceImpls.push(impl);
+        }
+    }
+
+    LOGI("haveAudio=%d, haveVideo=%d", haveAudio, haveVideo);
+}
+
+status_t MPEG2TSExtractor::feedMore() {
+    Mutex::Autolock autoLock(mLock);
+
+    static const size_t kTSPacketSize = 188;
+
+    uint8_t packet[kTSPacketSize];
+    ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize);
+
+    if (n < (ssize_t)kTSPacketSize) {
+        return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
+    }
+
+    mOffset += kTSPacketSize;
+    mParser->feedTSPacket(packet, kTSPacketSize);
+
+    return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool SniffMPEG2TS(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+    char header;
+    if (source->readAt(0, &header, 1) != 1 || header != 0x47) {
+        return false;
+    }
+
+    *confidence = 0.05f;
+    mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
+
+    return true;
+}
+
+}  // namespace android
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
new file mode 100644
index 0000000..4c83768
--- /dev/null
+++ b/packages/SystemUI/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := services
+
+LOCAL_PACKAGE_NAME := SystemUI
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
new file mode 100644
index 0000000..3f5b69d
--- /dev/null
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.systemui"
+        android:sharedUserId="android.uid.system">
+
+    <application
+        android:allowClearUserData="false"
+        android:label="@string/app_label"
+        android:icon="@drawable/ic_launcher_settings">
+                 
+        <receiver
+            android:name=".statusbar.StatusBarStarter"
+            >
+            <intent-filter>
+                <action android:name="com.android.internal.policy.statusbar.START" />
+            </intent-filter>
+        </receiver>
+        <service
+            android:name=".statusbar.PhoneStatusBarService"
+            android:exported="false"
+            />
+    </application>
+</manifest>
diff --git a/packages/SystemUI/MODULE_LICENSE_APACHE2 b/packages/SystemUI/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/packages/SystemUI/MODULE_LICENSE_APACHE2
diff --git a/packages/SystemUI/NOTICE b/packages/SystemUI/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/packages/SystemUI/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/core/res/res/drawable-hdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
similarity index 100%
rename from core/res/res/drawable-hdpi/battery_low_battery.png
rename to packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal.9.png
new file mode 100644
index 0000000..baafed6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable.9.png
new file mode 100644
index 0000000..175197b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png
new file mode 100644
index 0000000..ec1feff
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_pressed.9.png
new file mode 100644
index 0000000..c1f9a0f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/btn_default_small_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_selected.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_selected.9.png
new file mode 100644
index 0000000..0ea3f40
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/btn_default_small_selected.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_launcher_settings.png b/packages/SystemUI/res/drawable-hdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..ff34a7f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_launcher_settings.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png b/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png
new file mode 100644
index 0000000..744178f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notification_overlay.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/shade_bg.png b/packages/SystemUI/res/drawable-hdpi/shade_bg.png
new file mode 100644
index 0000000..3d00cd0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/shade_bg.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/shade_handlebar.9.png b/packages/SystemUI/res/drawable-hdpi/shade_handlebar.9.png
new file mode 100644
index 0000000..f313ffb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/shade_handlebar.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/shade_header_background.9.png b/packages/SystemUI/res/drawable-hdpi/shade_header_background.9.png
new file mode 100644
index 0000000..37b5fef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/shade_header_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_alarm.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_alarm.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_notify_alarm.png
rename to packages/SystemUI/res/drawable-hdpi/stat_notify_alarm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_more.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_more.png
new file mode 100755
index 0000000..1c7f9db
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_more.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth.png
new file mode 100644
index 0000000..96dc085
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_bluetooth_connected.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth_connected.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_bluetooth_connected.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_bluetooth_connected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_connected_1x.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_connected_3g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_connected_e.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_connected_g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_connected_h.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_in_1x.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_1x.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_in_3g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_in_e.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_in_g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_in_h.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_1x.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_inandout_1x.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_1x.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_inandout_3g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_inandout_e.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_inandout_g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_inandout_h.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_1x.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_out_1x.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_1x.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_3g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_out_3g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_out_e.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_out_g.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_h.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_data_out_h.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_h.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_gps_acquiring.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_gps_acquiring.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_gps_acquiring.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_gps_acquiring.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_no_sim.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_r_signal_0.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_r_signal_1.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_r_signal_2.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_r_signal_3.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_r_signal_4.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_r_signal_4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_ringer_silent.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_ringer_vibrate.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim0.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim0.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_signal_0.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_signal_1.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_signal_2.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_signal_3.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_signal_4.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_signal_flightmode.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_signal_null.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_tty_mode.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_tty_mode.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_tty_mode.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_tty_mode.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_wifi_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_wifi_signal_0.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_wifi_signal_1.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_wifi_signal_2.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_wifi_signal_3.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_wifi_signal_4.png
rename to packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png
new file mode 100644
index 0000000..a4be298
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_item_app_background_normal.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_item_app_background_normal.9.png
new file mode 100644
index 0000000..4fbfa4f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_item_app_background_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_focus.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_focus.9.png
new file mode 100644
index 0000000..0876bc6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_focus.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_normal.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_normal.9.png
new file mode 100644
index 0000000..c01c018
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_pressed.9.png
new file mode 100644
index 0000000..343e4ca
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_item_background_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/title_bar_portrait.9.png b/packages/SystemUI/res/drawable-hdpi/title_bar_portrait.9.png
new file mode 100644
index 0000000..70f7cc2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/title_bar_portrait.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/title_bar_shadow.9.png b/packages/SystemUI/res/drawable-hdpi/title_bar_shadow.9.png
new file mode 100644
index 0000000..e6dab63
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/title_bar_shadow.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-mdpi/battery_low_battery.png
similarity index 100%
rename from core/res/res/drawable-mdpi/battery_low_battery.png
rename to packages/SystemUI/res/drawable-mdpi/battery_low_battery.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal.9.png
new file mode 100644
index 0000000..bcedd5f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable.9.png
new file mode 100644
index 0000000..ac6260f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png
new file mode 100644
index 0000000..4ee1b3f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_pressed.9.png
new file mode 100644
index 0000000..25e38f4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/btn_default_small_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_selected.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_selected.9.png
new file mode 100644
index 0000000..cc209c6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/btn_default_small_selected.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_launcher_settings.png b/packages/SystemUI/res/drawable-mdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..b08ad3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_launcher_settings.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/battery_charge_fill_empty.9.png b/packages/SystemUI/res/drawable-mdpi/ic_notification_overlay.9.png
similarity index 76%
copy from core/res/res/drawable-mdpi/battery_charge_fill_empty.9.png
copy to packages/SystemUI/res/drawable-mdpi/ic_notification_overlay.9.png
index 9ed20ba..1a3063c4 100644
--- a/core/res/res/drawable-mdpi/battery_charge_fill_empty.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notification_overlay.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/shade_bg.png b/packages/SystemUI/res/drawable-mdpi/shade_bg.png
new file mode 100644
index 0000000..941d3b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/shade_bg.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/shade_handlebar.9.png b/packages/SystemUI/res/drawable-mdpi/shade_handlebar.9.png
new file mode 100644
index 0000000..9cbd9fe
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/shade_handlebar.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/battery_charge_fill_empty.9.png b/packages/SystemUI/res/drawable-mdpi/shade_header_background.9.png
similarity index 76%
copy from core/res/res/drawable-mdpi/battery_charge_fill_empty.9.png
copy to packages/SystemUI/res/drawable-mdpi/shade_header_background.9.png
index 9ed20ba..fa9a90c 100644
--- a/core/res/res/drawable-mdpi/battery_charge_fill_empty.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/shade_header_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_alarm.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_alarm.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_notify_alarm.png
rename to packages/SystemUI/res/drawable-mdpi/stat_notify_alarm.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_more.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_more.png
new file mode 100644
index 0000000..e129ba9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_notify_more.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_bluetooth_connected.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_bluetooth_connected.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_bluetooth_connected.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_bluetooth_connected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_connected_1x.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_connected_3g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_connected_e.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_connected_g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_connected_h.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_in_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_in_1x.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_in_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_in_3g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_in_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_in_e.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_in_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_in_g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_in_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_in_h.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_inandout_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_inandout_1x.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_inandout_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_inandout_3g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_inandout_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_e.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_inandout_e.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_e.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_inandout_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_inandout_g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_inandout_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_inandout_h.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_out_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_out_1x.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_out_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_out_3g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_out_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_out_e.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_out_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_out_g.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_out_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_data_out_h.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_gps_acquiring.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_gps_acquiring.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_gps_acquiring.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_gps_acquiring.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_no_sim.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_r_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_r_signal_0.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_r_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_r_signal_1.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_r_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_r_signal_2.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_r_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_r_signal_3.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_r_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_r_signal_4.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_r_signal_4.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_ringer_silent.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_ringer_vibrate.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim0.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim0.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_signal_0.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_signal_1.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_signal_2.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_signal_3.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_signal_4.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_signal_flightmode.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_signal_null.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_tty_mode.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_tty_mode.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_tty_mode.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_tty_mode.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_wifi_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_wifi_signal_0.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_wifi_signal_1.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_wifi_signal_2.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_wifi_signal_3.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_wifi_signal_4.png
rename to packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png
new file mode 100644
index 0000000..eb7c1a4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/battery_charge_fill_empty.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_item_app_background_normal.9.png
similarity index 78%
rename from core/res/res/drawable-mdpi/battery_charge_fill_empty.9.png
rename to packages/SystemUI/res/drawable-mdpi/status_bar_item_app_background_normal.9.png
index 9ed20ba..c079615 100644
--- a/core/res/res/drawable-mdpi/battery_charge_fill_empty.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_item_app_background_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_focus.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_focus.9.png
new file mode 100644
index 0000000..c3e24158
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_focus.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_normal.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_normal.9.png
new file mode 100644
index 0000000..b8e399d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_normal.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_pressed.9.png
new file mode 100644
index 0000000..02b4e9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_item_background_pressed.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/title_bar_portrait.9.png b/packages/SystemUI/res/drawable-mdpi/title_bar_portrait.9.png
new file mode 100644
index 0000000..13b18d8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/title_bar_portrait.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/title_bar_shadow.9.png b/packages/SystemUI/res/drawable-mdpi/title_bar_shadow.9.png
new file mode 100644
index 0000000..dbcefee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/title_bar_shadow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/btn_default_small.xml b/packages/SystemUI/res/drawable/btn_default_small.xml
new file mode 100644
index 0000000..5485ea0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/btn_default_small.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_window_focused="false" android:state_enabled="true"
+        android:drawable="@drawable/btn_default_small_normal" />
+    <item android:state_window_focused="false" android:state_enabled="false"
+        android:drawable="@drawable/btn_default_small_normal_disable" />
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/btn_default_small_pressed" />
+    <item android:state_focused="true" android:state_enabled="true"
+        android:drawable="@drawable/btn_default_small_selected" />
+    <item android:state_enabled="true"
+        android:drawable="@drawable/btn_default_small_normal" />
+    <item android:state_focused="true"
+        android:drawable="@drawable/btn_default_small_normal_disable_focused" />
+    <item
+         android:drawable="@drawable/btn_default_small_normal_disable" />
+</selector>
+
diff --git a/core/res/res/drawable/stat_sys_gps_acquiring_anim.xml b/packages/SystemUI/res/drawable/stat_sys_gps_acquiring_anim.xml
similarity index 90%
rename from core/res/res/drawable/stat_sys_gps_acquiring_anim.xml
rename to packages/SystemUI/res/drawable/stat_sys_gps_acquiring_anim.xml
index 954c19c..393697c 100644
--- a/core/res/res/drawable/stat_sys_gps_acquiring_anim.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_gps_acquiring_anim.xml
@@ -21,5 +21,5 @@
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:oneshot="false">
     <item android:drawable="@drawable/stat_sys_gps_acquiring" android:duration="500" />
-    <item android:drawable="@drawable/stat_sys_gps_on" android:duration="500" />
+    <item android:drawable="@*android:drawable/stat_sys_gps_on" android:duration="500" />
 </animation-list>
diff --git a/core/res/res/drawable/stat_sys_roaming_cdma_flash.xml b/packages/SystemUI/res/drawable/stat_sys_roaming_cdma_flash.xml
similarity index 100%
rename from core/res/res/drawable/stat_sys_roaming_cdma_flash.xml
rename to packages/SystemUI/res/drawable/stat_sys_roaming_cdma_flash.xml
diff --git a/core/res/res/layout/battery_low.xml b/packages/SystemUI/res/layout/battery_low.xml
similarity index 100%
rename from core/res/res/layout/battery_low.xml
rename to packages/SystemUI/res/layout/battery_low.xml
diff --git a/core/res/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
similarity index 70%
rename from core/res/res/layout/status_bar.xml
rename to packages/SystemUI/res/layout/status_bar.xml
index 2237ee4..5fe8e79 100644
--- a/core/res/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -19,8 +19,9 @@
 -->
 
 <!--    android:background="@drawable/status_bar_closed_default_background" -->
-<com.android.server.status.StatusBarView xmlns:android="http://schemas.android.com/apk/res/android" 
-    android:background="@drawable/statusbar_background"
+<com.android.systemui.statusbar.StatusBarView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:background="@drawable/status_bar_background"
     android:orientation="vertical"
     android:focusable="true"
     android:descendantFocusability="afterDescendants"
@@ -31,7 +32,7 @@
         android:layout_height="match_parent"
         android:orientation="horizontal">
             
-        <com.android.server.status.IconMerger android:id="@+id/notificationIcons"
+        <com.android.systemui.statusbar.IconMerger android:id="@+id/notificationIcons"
             android:layout_width="0dip"
             android:layout_weight="1"
             android:layout_height="match_parent"
@@ -47,6 +48,17 @@
             android:paddingRight="6dip"
             android:gravity="center_vertical"
             android:orientation="horizontal"/>    
+
+        <com.android.systemui.statusbar.Clock
+            android:textAppearance="@*android:style/TextAppearance.StatusBar.Icon"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:singleLine="true"
+            android:paddingRight="6dip"
+            android:textSize="16sp"
+            android:textStyle="bold"
+            android:gravity="center_vertical|left"
+            />
     </LinearLayout>
         
     <LinearLayout android:id="@+id/ticker"
@@ -60,44 +72,44 @@
             android:layout_height="match_parent"
             android:layout_marginRight="8dip"
             >
-            <com.android.server.status.AnimatedImageView
+            <com.android.systemui.statusbar.AnimatedImageView
                 android:layout_width="25dip"
                 android:layout_height="25dip"
                 />
-            <com.android.server.status.AnimatedImageView
+            <com.android.systemui.statusbar.AnimatedImageView
                 android:layout_width="25dip"
                 android:layout_height="25dip"
                 />
         </ImageSwitcher>
-        <com.android.server.status.TickerView android:id="@+id/tickerText"
+        <com.android.systemui.statusbar.TickerView android:id="@+id/tickerText"
             android:layout_width="0dip"
             android:layout_weight="1"
             android:layout_height="wrap_content"
             android:paddingTop="2dip"
             android:paddingRight="10dip">
             <TextView
-                android:textAppearance="@style/TextAppearance.StatusBar.Ticker"
+                android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:singleLine="true"
                 />
             <TextView
-                android:textAppearance="@style/TextAppearance.StatusBar.Ticker"
+                android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:singleLine="true"
                 />
-        </com.android.server.status.TickerView>
+        </com.android.systemui.statusbar.TickerView>
     </LinearLayout>
 
-    <com.android.server.status.DateView android:id="@+id/date"
-        android:textAppearance="@style/TextAppearance.StatusBar.Icon"
+    <com.android.systemui.statusbar.DateView android:id="@+id/date"
+        android:textAppearance="@*android:style/TextAppearance.StatusBar.Icon"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:singleLine="true"
         android:gravity="center_vertical|left"
         android:paddingLeft="6px"
         android:paddingRight="6px"
-        android:background="@drawable/statusbar_background"
+        android:background="@drawable/status_bar_background"
         />
-</com.android.server.status.StatusBarView>
+</com.android.systemui.statusbar.StatusBarView>
diff --git a/core/res/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
similarity index 77%
rename from core/res/res/layout/status_bar_expanded.xml
rename to packages/SystemUI/res/layout/status_bar_expanded.xml
index 68eb922..b5b1b50 100644
--- a/core/res/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -18,7 +18,7 @@
 */
 -->
 
-<com.android.server.status.ExpandedView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.systemui.statusbar.ExpandedView xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:focusable="true"
     android:descendantFocusability="afterDescendants"
@@ -31,9 +31,9 @@
         android:paddingTop="3dp"
         android:paddingBottom="5dp"
         android:paddingRight="3dp"
-        android:background="@drawable/status_bar_header_background"
+        android:background="@drawable/shade_header_background"
         >
-        <LinearLayout
+        <com.android.systemui.statusbar.CarrierLabel
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
@@ -41,25 +41,10 @@
             android:layout_marginLeft="5dp"
             android:layout_gravity="center_vertical"
             android:paddingBottom="1dp"
-            android:orientation="vertical"
-            >
-                <TextView android:id="@+id/plmnLabel"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center_vertical"
-                    android:textAppearance="?android:attr/textAppearanceLarge"
-                    android:textColor="?android:attr/textColorSecondary"
-                    android:paddingLeft="4dp"
-                    />
-                <TextView android:id="@+id/spnLabel"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center_vertical"
-                    android:textAppearance="?android:attr/textAppearanceLarge"
-                    android:textColor="?android:attr/textColorSecondary"
-                    android:paddingLeft="4dp"
-                    />
-        </LinearLayout>
+            android:paddingLeft="4dp"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textColor="?android:attr/textColorSecondary"
+            />
         <TextView android:id="@+id/clear_all_button"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -67,7 +52,7 @@
             android:layout_marginTop="4dp"
             android:layout_marginBottom="1dp"
             android:textSize="14sp"
-            android:textColor="?android:attr/textColorPrimaryInverse"
+            android:textColor="#ff000000"
             android:text="@string/status_bar_clear_all_button"
             style="?android:attr/buttonStyle"
             android:paddingLeft="15dp"
@@ -87,7 +72,7 @@
             android:layout_height="match_parent"
             android:fadingEdge="none"
             >
-            <com.android.server.status.NotificationLinearLayout
+            <com.android.systemui.statusbar.NotificationLinearLayout
                 android:id="@+id/notificationLinearLayout"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
@@ -130,7 +115,7 @@
                     android:layout_height="wrap_content"
                     android:orientation="vertical"
                     />
-            </com.android.server.status.NotificationLinearLayout>
+            </com.android.systemui.statusbar.NotificationLinearLayout>
         </ScrollView>
 
         <ImageView
@@ -141,4 +126,4 @@
         />
 
     </FrameLayout>
-</com.android.server.status.ExpandedView>
+</com.android.systemui.statusbar.ExpandedView>
diff --git a/core/res/res/layout/status_bar_icon.xml b/packages/SystemUI/res/layout/status_bar_icon.xml
similarity index 95%
rename from core/res/res/layout/status_bar_icon.xml
rename to packages/SystemUI/res/layout/status_bar_icon.xml
index 0536792..21d606f 100644
--- a/core/res/res/layout/status_bar_icon.xml
+++ b/packages/SystemUI/res/layout/status_bar_icon.xml
@@ -25,7 +25,7 @@
     android:layout_height="25dp"
     >
 
-    <com.android.server.status.AnimatedImageView android:id="@+id/image"
+    <com.android.systemui.statusbar.AnimatedImageView android:id="@+id/image"
         android:layout_width="match_parent" 
         android:layout_height="match_parent"
         />
diff --git a/core/res/res/layout/status_bar_tracking.xml b/packages/SystemUI/res/layout/status_bar_tracking.xml
similarity index 77%
rename from core/res/res/layout/status_bar_tracking.xml
rename to packages/SystemUI/res/layout/status_bar_tracking.xml
index c0a7a97..a2b40e6 100644
--- a/core/res/res/layout/status_bar_tracking.xml
+++ b/packages/SystemUI/res/layout/status_bar_tracking.xml
@@ -15,7 +15,8 @@
     limitations under the License.
 -->
 
-<com.android.server.status.TrackingView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.systemui.statusbar.TrackingView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:visibility="gone"
     android:focusable="true"
@@ -25,13 +26,13 @@
     android:paddingRight="0px"
     >
 
-    <com.android.server.status.TrackingPatternView
+    <com.android.systemui.statusbar.TrackingPatternView
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_weight="1"
         />
 
-    <com.android.server.status.CloseDragHandle android:id="@+id/close"
+    <com.android.systemui.statusbar.CloseDragHandle android:id="@+id/close"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="vertical"
@@ -41,8 +42,9 @@
             android:layout_height="wrap_content"
             android:layout_gravity="bottom"
             android:scaleType="fitXY"
-            android:src="@drawable/status_bar_close_on"/>
+            android:src="@drawable/shade_handlebar"
+            />
 
-    </com.android.server.status.CloseDragHandle>
+    </com.android.systemui.statusbar.CloseDragHandle>
 
-</com.android.server.status.TrackingView>
+</com.android.systemui.statusbar.TrackingView>
diff --git a/packages/SystemUI/res/values/arrays.xml b/packages/SystemUI/res/values/arrays.xml
new file mode 100644
index 0000000..dbb0e0f
--- /dev/null
+++ b/packages/SystemUI/res/values/arrays.xml
@@ -0,0 +1,28 @@
+<?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">
+
+    <!-- Do not translate. Defines the slots for the right-hand side icons.  That is to say, the
+         icons in the status bar that are not notifications. -->
+    <string-array name="status_bar_icon_order">
+        <item><xliff:g id="id">TODO: Remove; not used.</xliff:g></item>
+    </string-array>
+
+</resources>
diff --git a/core/res/res/drawable/status_icon_background.xml b/packages/SystemUI/res/values/config.xml
similarity index 61%
rename from core/res/res/drawable/status_icon_background.xml
rename to packages/SystemUI/res/values/config.xml
index 9846165..8ea46e5 100644
--- a/core/res/res/drawable/status_icon_background.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/drawable/status_icon_background.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*
+** 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. 
@@ -18,7 +17,10 @@
 */
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_selected="true" android:drawable="@drawable/icon_highlight_rectangle" />
-    <item android:drawable="@color/transparent" />
-</selector>
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Control whether status bar should distinguish HSPA data icon form UMTS data icon on devices -->
+    <bool name="config_hspa_data_distinguishable">false</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values/defaults.xml b/packages/SystemUI/res/values/defaults.xml
new file mode 100644
index 0000000..34302c4
--- /dev/null
+++ b/packages/SystemUI/res/values/defaults.xml
@@ -0,0 +1,78 @@
+<?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.
+ */
+-->
+<resources>
+    <bool name="def_dim_screen">true</bool>
+    <integer name="def_screen_off_timeout">60000</integer>
+    <bool name="def_airplane_mode_on">false</bool>
+    <!-- Comma-separated list of bluetooth, wifi, and cell. -->
+    <string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi</string>
+    <string name="airplane_mode_toggleable_radios" translatable="false">wifi</string>
+    <bool name="def_auto_time">true</bool>
+    <bool name="def_accelerometer_rotation">true</bool>
+    <!-- Default screen brightness, from 0 to 255.  102 is 40%. -->
+    <integer name="def_screen_brightness">102</integer>
+    <bool name="def_screen_brightness_automatic_mode">false</bool>
+    <fraction name="def_window_animation_scale">100%</fraction>
+    <fraction name="def_window_transition_scale">100%</fraction>
+    <bool name="def_haptic_feedback">true</bool>
+    
+    <bool name="def_bluetooth_on">false</bool>
+    <bool name="def_install_non_market_apps">false</bool>
+    <!-- Comma-separated list of location providers. 
+         Network location is off by default because it requires
+         user opt-in via Setup Wizard or Settings.  
+    -->
+    <string name="def_location_providers_allowed" translatable="false">gps</string>
+    <bool name="assisted_gps_enabled">true</bool>
+    <!--  0 == mobile, 1 == wifi. -->
+    <integer name="def_network_preference">1</integer>
+    <bool name="def_usb_mass_storage_enabled">true</bool>
+    <bool name="def_wifi_on">false</bool>
+    <bool name="def_networks_available_notification_on">true</bool>
+    
+    <bool name="def_backup_enabled">false</bool>
+    <string name="def_backup_transport" translatable="false"></string>
+    <!-- Default value for whether or not to pulse the notification LED when there is a 
+         pending notification -->
+    <bool name="def_notification_pulse">true</bool>
+
+    <bool name="def_mount_play_notification_snd">true</bool>
+    <bool name="def_mount_ums_autostart">false</bool>
+    <bool name="def_mount_ums_prompt">true</bool>
+    <bool name="def_mount_ums_notify_enabled">true</bool>
+    <!-- Enable User preference for setting install location -->
+    <bool name="set_install_location">true</bool>
+    <!-- Default install location if user preference for setting install location is turned on. -->
+    <integer name="def_install_location">2</integer>
+
+    <!-- user interface sound effects -->
+    <integer name="def_power_sounds_enabled">1</integer>
+    <string name="def_low_battery_sound" translatable="false">/system/media/audio/ui/LowBattery.ogg</string>
+    <integer name="def_dock_sounds_enabled">0</integer>
+    <string name="def_desk_dock_sound" translatable="false">/system/media/audio/ui/Dock.ogg</string>
+    <string name="def_desk_undock_sound" translatable="false">/system/media/audio/ui/Undock.ogg</string>
+    <string name="def_car_dock_sound" translatable="false">/system/media/audio/ui/Dock.ogg</string>
+    <string name="def_car_undock_sound" translatable="false">/system/media/audio/ui/Undock.ogg</string>
+    <integer name="def_lockscreen_sounds_enabled">0</integer>
+    <string name="def_lock_sound" translatable="false">/system/media/audio/ui/Lock.ogg</string>
+    <string name="def_unlock_sound" translatable="false">/system/media/audio/ui/Unlock.ogg</string>
+
+    <!-- Default for Settings.System.VIBRATE_IN_SILENT -->
+    <bool name="def_vibrate_in_silent">true</bool>
+</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
new file mode 100644
index 0000000..93cf377
--- /dev/null
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+*/
+-->
+<resources>
+    <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
+    <dimen name="status_bar_edge_ignore">5dp</dimen>
+</resources>
+
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
new file mode 100644
index 0000000..ba3a3d1
--- /dev/null
+++ b/packages/SystemUI/res/values/strings.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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Name of the status bar as seen in the applications info settings page. -->
+    <string name="app_label">Status Bar</string>
+
+    <!-- The text for the button in the notification window-shade that clears
+         all of the currently visible notifications. -->
+    <string name="status_bar_clear_all_button">Clear</string>
+
+    <!-- The label in the bar at the top of the status bar when there are no notifications
+         showing. -->
+    <string name="status_bar_no_notifications_title">No notifications</string>
+
+    <!-- The label for the group of notifications for ongoing events in the opened version of
+         the status bar.  An ongoing call is the prime example of this.  The MP3 music player
+         might be another example.  -->
+    <string name="status_bar_ongoing_events_title">Ongoing</string>
+
+    <!-- The label for the group of notifications for recent events in the opened version of
+         the status bar.  Recently received text messsages (SMS), emails, calendar alerts, etc. -->
+    <string name="status_bar_latest_events_title">Notifications</string>
+
+    <!-- When the battery is low, this is displayed to the user in a dialog.  The title of the low battery alert. -->
+    <string name="battery_low_title">Please connect charger</string>
+
+    <!-- When the battery is low, this is displayed to the user in a dialog. The subtitle of the low battery alert. -->
+    <string name="battery_low_subtitle">The battery is getting low:</string>
+
+    <!-- A message that appears when the battery level is getting low in a dialog.  This is appened to the subtitle of the low battery alert. -->
+    <string name="battery_low_percent_format"><xliff:g id="number">%d%%</xliff:g>
+    or less remaining.</string>
+
+    <!-- When the battery is low, this is the label of the button to go to the
+         power usage activity to find out what drained the battery. -->
+    <string name="battery_low_why">Battery use</string>
+
+</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
new file mode 100644
index 0000000..10fa930
--- /dev/null
+++ b/packages/SystemUI/res/values/styles.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <style name="TextAppearance.StatusBar.Title" parent="@android:style/TextAppearance.StatusBar">
+        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+        <item name="android:textStyle">bold</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
+
+
+
+</resources>
diff --git a/packages/SystemUI/res/xml/bookmarks.xml b/packages/SystemUI/res/xml/bookmarks.xml
new file mode 100644
index 0000000..dfaeeaf
--- /dev/null
+++ b/packages/SystemUI/res/xml/bookmarks.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<bookmarks>
+    <bookmark
+        package="com.android.browser"
+        class="com.android.browser.BrowserActivity"
+        shortcut="b" />
+    <bookmark
+        package="com.android.contacts"
+        class="com.android.contacts.DialtactsContactsEntryActivity"
+        shortcut="c" />
+    <bookmark
+        package="com.android.email"
+        class="com.android.email.activity.Welcome"
+        shortcut="e" />
+    <bookmark
+        package="com.google.android.gm"
+        class="com.google.android.gm.ConversationListActivityGmail"
+        shortcut="g" />
+    <bookmark
+        package="com.android.im"
+        class="com.android.im.app.LandingPage"
+        shortcut="i" />
+    <bookmark
+        package="com.android.calendar"
+        class="com.android.calendar.LaunchActivity"
+        shortcut="l" />
+<!--
+    <bookmark
+        package="com.google.android.apps.maps"
+        class="com.google.android.maps.MapsActivity"
+        shortcut="m" />
+-->
+    <bookmark
+        package="com.android.music"
+        class="com.android.music.MusicBrowserActivity"
+        shortcut="p" />
+    <bookmark
+        package="com.android.mms"
+        class="com.android.mms.ui.ConversationList"
+        shortcut="s" />
+</bookmarks>
diff --git a/services/java/com/android/server/status/AnimatedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
similarity index 97%
rename from services/java/com/android/server/status/AnimatedImageView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
index 97df065..70d4d6a 100644
--- a/services/java/com/android/server/status/AnimatedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.graphics.drawable.AnimationDrawable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java b/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java
new file mode 100644
index 0000000..d89d093
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CarrierLabel.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.provider.Telephony;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.View;
+import android.widget.TextView;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+import com.android.internal.R;
+
+/**
+ * This widget display an analogic clock with two hands for hours and
+ * minutes.
+ */
+public class CarrierLabel extends TextView {
+    private boolean mAttached;
+
+    public CarrierLabel(Context context) {
+        this(context, null);
+    }
+
+    public CarrierLabel(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public CarrierLabel(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        updateNetworkName(false, null, false, null);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        if (!mAttached) {
+            mAttached = true;
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION);
+            getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (mAttached) {
+            getContext().unregisterReceiver(mIntentReceiver);
+            mAttached = false;
+        }
+    }
+
+    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Telephony.Intents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
+                updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false),
+                        intent.getStringExtra(Telephony.Intents.EXTRA_SPN),
+                        intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false),
+                        intent.getStringExtra(Telephony.Intents.EXTRA_PLMN));
+            }
+        }
+    };
+
+    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
+        if (false) {
+            Slog.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
+                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
+        }
+        StringBuilder str = new StringBuilder();
+        boolean something = false;
+        if (showPlmn && plmn != null) {
+            str.append(plmn);
+            something = true;
+        }
+        if (showSpn && spn != null) {
+            if (something) {
+                str.append(' ');
+            }
+            str.append(spn);
+            something = true;
+        }
+        if (something) {
+            setText(str.toString());
+        } else {
+            setText(com.android.internal.R.string.lockscreen_carrier_default);
+        }
+    }
+
+    
+}
+
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/Clock.java
new file mode 100644
index 0000000..9fc8df5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/Clock.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.format.DateFormat;
+import android.text.style.CharacterStyle;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.StyleSpan;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+import com.android.internal.R;
+
+/**
+ * This widget display an analogic clock with two hands for hours and
+ * minutes.
+ */
+public class Clock extends TextView {
+    private boolean mAttached;
+    private Calendar mCalendar;
+    private String mClockFormatString;
+    private SimpleDateFormat mClockFormat;
+
+    private static final int AM_PM_STYLE_NORMAL  = 0;
+    private static final int AM_PM_STYLE_SMALL   = 1;
+    private static final int AM_PM_STYLE_GONE    = 2;
+
+    private static final int AM_PM_STYLE = AM_PM_STYLE_GONE;
+
+    public Clock(Context context) {
+        this(context, null);
+    }
+
+    public Clock(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public Clock(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        if (!mAttached) {
+            mAttached = true;
+            IntentFilter filter = new IntentFilter();
+
+            filter.addAction(Intent.ACTION_TIME_TICK);
+            filter.addAction(Intent.ACTION_TIME_CHANGED);
+            filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+            filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+
+            getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());
+        }
+
+        // NOTE: It's safe to do these after registering the receiver since the receiver always runs
+        // in the main thread, therefore the receiver can't run before this method returns.
+
+        // The time zone may have changed while the receiver wasn't registered, so update the Time
+        mCalendar = Calendar.getInstance(TimeZone.getDefault());
+
+        // Make sure we update to the current time
+        updateClock();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (mAttached) {
+            getContext().unregisterReceiver(mIntentReceiver);
+            mAttached = false;
+        }
+    }
+
+    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
+                String tz = intent.getStringExtra("time-zone");
+                mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
+                if (mClockFormat != null) {
+                    mClockFormat.setTimeZone(mCalendar.getTimeZone());
+                }
+            }
+            updateClock();
+        }
+    };
+
+    final void updateClock() {
+        mCalendar.setTimeInMillis(System.currentTimeMillis());
+        setText(getSmallTime());
+    }
+
+    private final CharSequence getSmallTime() {
+        Context context = getContext();
+        boolean b24 = DateFormat.is24HourFormat(context);
+        int res;
+
+        if (b24) {
+            res = R.string.twenty_four_hour_time_format;
+        } else {
+            res = R.string.twelve_hour_time_format;
+        }
+
+        final char MAGIC1 = '\uEF00';
+        final char MAGIC2 = '\uEF01';
+
+        SimpleDateFormat sdf;
+        String format = context.getString(res);
+        if (!format.equals(mClockFormatString)) {
+            /*
+             * Search for an unquoted "a" in the format string, so we can
+             * add dummy characters around it to let us find it again after
+             * formatting and change its size.
+             */
+            if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) {
+                int a = -1;
+                boolean quoted = false;
+                for (int i = 0; i < format.length(); i++) {
+                    char c = format.charAt(i);
+
+                    if (c == '\'') {
+                        quoted = !quoted;
+                    }
+                    if (!quoted && c == 'a') {
+                        a = i;
+                        break;
+                    }
+                }
+
+                if (a >= 0) {
+                    // Move a back so any whitespace before AM/PM is also in the alternate size.
+                    final int b = a;
+                    while (a > 0 && Character.isWhitespace(format.charAt(a-1))) {
+                        a--;
+                    }
+                    format = format.substring(0, a) + MAGIC1 + format.substring(a, b)
+                        + "a" + MAGIC2 + format.substring(b + 1);
+                }
+            }
+
+            mClockFormat = sdf = new SimpleDateFormat(format);
+            mClockFormatString = format;
+        } else {
+            sdf = mClockFormat;
+        }
+        String result = sdf.format(mCalendar.getTime());
+
+        if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) {
+            int magic1 = result.indexOf(MAGIC1);
+            int magic2 = result.indexOf(MAGIC2);
+            if (magic1 >= 0 && magic2 > magic1) {
+                SpannableStringBuilder formatted = new SpannableStringBuilder(result);
+                if (AM_PM_STYLE == AM_PM_STYLE_GONE) {
+                    formatted.delete(magic1, magic2+1);
+                } else {
+                    if (AM_PM_STYLE == AM_PM_STYLE_SMALL) {
+                        CharacterStyle style = new RelativeSizeSpan(0.7f);
+                        formatted.setSpan(style, magic1, magic2,
+                                          Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+                    }
+                    formatted.delete(magic2, magic2 + 1);
+                    formatted.delete(magic1, magic1 + 1);
+                }
+                return formatted;
+            }
+        }
+ 
+        return result;
+
+    }
+}
+
diff --git a/services/java/com/android/server/status/CloseDragHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
similarity index 94%
rename from services/java/com/android/server/status/CloseDragHandle.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
index ad1ac4d..0f6723e 100644
--- a/services/java/com/android/server/status/CloseDragHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.util.AttributeSet;
@@ -23,7 +23,7 @@
 
 
 public class CloseDragHandle extends LinearLayout {
-    StatusBarService mService;
+    PhoneStatusBarService mService;
 
     public CloseDragHandle(Context context, AttributeSet attrs) {
         super(context, attrs);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
new file mode 100644
index 0000000..f9347b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+
+import com.android.internal.statusbar.IStatusBar;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.StatusBarNotification;
+
+/**
+ * This class takes the functions from IStatusBar that come in on
+ * binder pool threads and posts messages to get them onto the main
+ * thread, and calls onto Callbacks.  It also takes care of
+ * coalescing these calls so they don't stack up.  For the calls
+ * are coalesced, note that they are all idempotent.
+ */
+class CommandQueue extends IStatusBar.Stub {
+    private static final String TAG = "StatusBar.CommandQueue";
+
+    private static final int MSG_MASK = 0xffff0000;
+    private static final int INDEX_MASK = 0x0000ffff;
+
+    private static final int MSG_ICON = 0x00010000;
+    private static final int OP_SET_ICON = 1;
+    private static final int OP_REMOVE_ICON = 2;
+
+    private static final int MSG_ADD_NOTIFICATION = 0x00020000;
+    private static final int MSG_UPDATE_NOTIFICATION = 0x00030000;
+    private static final int MSG_REMOVE_NOTIFICATION = 0x00040000;
+
+    private static final int MSG_DISABLE = 0x00050000;
+
+    private static final int MSG_SET_VISIBILITY = 0x00060000;
+    private static final int OP_EXPAND = 1;
+    private static final int OP_COLLAPSE = 2;
+
+    private StatusBarIconList mList;
+    private Callbacks mCallbacks;
+    private Handler mHandler = new H();
+
+    private class NotificationQueueEntry {
+        IBinder key;
+        StatusBarNotification notification;
+    }
+
+    /**
+     * These methods are called back on the main thread.
+     */
+    public interface Callbacks {
+        public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon);
+        public void updateIcon(String slot, int index, int viewIndex,
+                StatusBarIcon old, StatusBarIcon icon);
+        public void removeIcon(String slot, int index, int viewIndex);
+        public void addNotification(IBinder key, StatusBarNotification notification);
+        public void updateNotification(IBinder key, StatusBarNotification notification);
+        public void removeNotification(IBinder key);
+        public void disable(int state);
+        public void animateExpand();
+        public void animateCollapse();
+    }
+
+    public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
+        mCallbacks = callbacks;
+        mList = list;
+    }
+
+    public void setIcon(int index, StatusBarIcon icon) {
+        synchronized (mList) {
+            int what = MSG_ICON | index;
+            mHandler.removeMessages(what);
+            mHandler.obtainMessage(what, OP_SET_ICON, 0, icon.clone()).sendToTarget();
+        }
+    }
+
+    public void removeIcon(int index) {
+        synchronized (mList) {
+            int what = MSG_ICON | index;
+            mHandler.removeMessages(what);
+            mHandler.obtainMessage(what, OP_REMOVE_ICON, 0, null).sendToTarget();
+        }
+    }
+
+    public void addNotification(IBinder key, StatusBarNotification notification) {
+        synchronized (mList) {
+            NotificationQueueEntry ne = new NotificationQueueEntry();
+            ne.key = key;
+            ne.notification = notification;
+            mHandler.obtainMessage(MSG_ADD_NOTIFICATION, 0, 0, ne).sendToTarget();
+        }
+    }
+
+    public void updateNotification(IBinder key, StatusBarNotification notification) {
+        synchronized (mList) {
+            NotificationQueueEntry ne = new NotificationQueueEntry();
+            ne.key = key;
+            ne.notification = notification;
+            mHandler.obtainMessage(MSG_UPDATE_NOTIFICATION, 0, 0, ne).sendToTarget();
+        }
+    }
+
+    public void removeNotification(IBinder key) {
+        synchronized (mList) {
+            mHandler.obtainMessage(MSG_REMOVE_NOTIFICATION, 0, 0, key).sendToTarget();
+        }
+    }
+
+    public void disable(int state) {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_DISABLE);
+            mHandler.obtainMessage(MSG_DISABLE, state, 0, null).sendToTarget();
+        }
+    }
+
+    public void animateExpand() {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_SET_VISIBILITY);
+            mHandler.obtainMessage(MSG_SET_VISIBILITY, OP_EXPAND, 0, null).sendToTarget();
+        }
+    }
+
+    public void animateCollapse() {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_SET_VISIBILITY);
+            mHandler.obtainMessage(MSG_SET_VISIBILITY, OP_COLLAPSE, 0, null).sendToTarget();
+        }
+    }
+
+    private final class H extends Handler {
+        public void handleMessage(Message msg) {
+            final int what = msg.what & MSG_MASK;
+            switch (what) {
+                case MSG_ICON: {
+                    final int index = msg.what & INDEX_MASK;
+                    final int viewIndex = mList.getViewIndex(index);
+                    switch (msg.arg1) {
+                        case OP_SET_ICON: {
+                            StatusBarIcon icon = (StatusBarIcon)msg.obj;
+                            StatusBarIcon old = mList.getIcon(index);
+                            if (old == null) {
+                                mList.setIcon(index, icon);
+                                mCallbacks.addIcon(mList.getSlot(index), index, viewIndex, icon);
+                            } else {
+                                mList.setIcon(index, icon);
+                                mCallbacks.updateIcon(mList.getSlot(index), index, viewIndex,
+                                        old, icon);
+                            }
+                            break;
+                        }
+                        case OP_REMOVE_ICON:
+                            mList.removeIcon(index);
+                            mCallbacks.removeIcon(mList.getSlot(index), index, viewIndex);
+                            break;
+                    }
+                    break;
+                }
+                case MSG_ADD_NOTIFICATION: {
+                    final NotificationQueueEntry ne = (NotificationQueueEntry)msg.obj;
+                    mCallbacks.addNotification(ne.key, ne.notification);
+                    break;
+                }
+                case MSG_UPDATE_NOTIFICATION: {
+                    final NotificationQueueEntry ne = (NotificationQueueEntry)msg.obj;
+                    mCallbacks.updateNotification(ne.key, ne.notification);
+                    break;
+                }
+                case MSG_REMOVE_NOTIFICATION: {
+                    mCallbacks.removeNotification((IBinder)msg.obj);
+                    break;
+                }
+                case MSG_DISABLE:
+                    mCallbacks.disable(msg.arg1);
+                    break;
+                case MSG_SET_VISIBILITY:
+                    if (msg.arg1 == OP_EXPAND) {
+                        mCallbacks.animateExpand();
+                    } else {
+                        mCallbacks.animateCollapse();
+                    }
+            }
+        }
+    }
+}
+
diff --git a/services/java/com/android/server/status/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DateView.java
similarity index 98%
rename from services/java/com/android/server/status/DateView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/DateView.java
index c04fb45..e6d3a7e 100644
--- a/services/java/com/android/server/status/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DateView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
diff --git a/services/java/com/android/server/status/ExpandedView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
similarity index 84%
rename from services/java/com/android/server/status/ExpandedView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
index cb37f90..c5b901f 100644
--- a/services/java/com/android/server/status/ExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.util.AttributeSet;
@@ -27,7 +27,7 @@
 
 
 public class ExpandedView extends LinearLayout {
-    StatusBarService mService;
+    PhoneStatusBarService mService;
     int mPrevHeight = -1;
 
     public ExpandedView(Context context, AttributeSet attrs) {
@@ -50,9 +50,10 @@
          super.onLayout(changed, left, top, right, bottom);
          int height = bottom - top;
          if (height != mPrevHeight) {
-             //Slog.d(StatusBarService.TAG, "height changed old=" + mPrevHeight + " new=" + height);
+             //Slog.d(PhoneStatusBarService.TAG, "height changed old=" + mPrevHeight
+             //     + " new=" + height);
              mPrevHeight = height;
-             mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE);
+             mService.updateExpandedViewPos(PhoneStatusBarService.EXPANDED_LEAVE_ALONE);
          }
      }
 }
diff --git a/services/java/com/android/server/status/FixedSizeDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/FixedSizeDrawable.java
similarity index 97%
rename from services/java/com/android/server/status/FixedSizeDrawable.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/FixedSizeDrawable.java
index dbfcb2c..eb22b61 100644
--- a/services/java/com/android/server/status/FixedSizeDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FixedSizeDrawable.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.graphics.drawable.Drawable;
 import android.graphics.Canvas;
diff --git a/services/java/com/android/server/status/IconMerger.java b/packages/SystemUI/src/com/android/systemui/statusbar/IconMerger.java
similarity index 80%
rename from services/java/com/android/server/status/IconMerger.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/IconMerger.java
index aa702ae..027bed4a 100644
--- a/services/java/com/android/server/status/IconMerger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/IconMerger.java
@@ -14,23 +14,39 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.os.Handler;
 import android.util.AttributeSet;
+import android.util.Slog;
 import android.view.View;
 import android.widget.LinearLayout;
 
+import com.android.systemui.R;
+
 
 public class IconMerger extends LinearLayout {
-    StatusBarService service;
-    StatusBarIcon moreIcon;
+    private static final String TAG = "IconMerger";
+
+    private StatusBarIconView mMoreView;
 
     public IconMerger(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
+    public void addMoreView(StatusBarIconView v, LinearLayout.LayoutParams lp) {
+        super.addView(v, lp);
+        mMoreView = v;
+    }
+
+    public void addView(StatusBarIconView v, int index, LinearLayout.LayoutParams lp) {
+        if (index == 0) {
+            throw new RuntimeException("Attempt to put view before the more view: " + v);
+        }
+        super.addView(v, index, lp);
+    }
+
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
@@ -50,13 +66,12 @@
         }
 
         // find the first visible one that isn't the more icon
-        View moreView = null;
+        final StatusBarIconView moreView = mMoreView;
         int fitLeft = -1;
         int startIndex = -1;
         for (i=0; i<N; i++) {
             final View child = getChildAt(i);
-            if (com.android.internal.R.drawable.stat_notify_more == child.getId()) {
-                moreView = child;
+            if (child == moreView) {
                 startIndex = i+1;
             }
             else if (child.getVisibility() != GONE) {
@@ -66,7 +81,11 @@
         }
 
         if (moreView == null || startIndex < 0) {
-            throw new RuntimeException("Status Bar / IconMerger moreView == null");
+            return;
+            /*
+            throw new RuntimeException("Status Bar / IconMerger moreView == " + moreView
+                    + " startIndex=" + startIndex);
+            */
         }
         
         // if it fits without the more icon, then hide the more icon and update fitLeft
@@ -84,14 +103,14 @@
         int breakingPoint = fitLeft + extra + adjust;
         int number = 0;
         for (i=startIndex; i<N; i++) {
-            final View child = getChildAt(i);
+            final StatusBarIconView child = (StatusBarIconView)getChildAt(i);
             if (child.getVisibility() != GONE) {
                 int childLeft = child.getLeft();
                 int childRight = child.getRight();
                 if (childLeft < breakingPoint) {
                     // hide this one
                     child.layout(0, child.getTop(), 0, child.getBottom());
-                    int n = this.service.getIconNumberForView(child);
+                    int n = child.getStatusBarIcon().number;
                     if (n == 0) {
                         number += 1;
                     } else if (n > 0) {
@@ -115,7 +134,7 @@
         // and provide the value later.  We're the only one changing this value show it
         // should be ordered correctly.
         if (false) {
-            this.moreIcon.update(number);
+            // TODO this.moreIcon.update(number);
         } else {
             mBugWorkaroundNumber = number;
             mBugWorkaroundHandler.post(mBugWorkaroundRunnable);
@@ -126,8 +145,10 @@
     private Handler mBugWorkaroundHandler = new Handler();
     private Runnable mBugWorkaroundRunnable = new Runnable() {
         public void run() {
+            /* TODO
             IconMerger.this.moreIcon.update(mBugWorkaroundNumber);
             IconMerger.this.moreIcon.view.invalidate();
+            */
         }
     };
 }
diff --git a/services/java/com/android/server/status/NotificationLinearLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
similarity index 67%
copy from services/java/com/android/server/status/NotificationLinearLayout.java
copy to packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
index 2fdf956..1e89624 100644
--- a/services/java/com/android/server/status/NotificationLinearLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
@@ -14,16 +14,21 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.widget.LinearLayout;
+import android.util.Slog;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
 
+public class LatestItemView extends FrameLayout {
 
-public class NotificationLinearLayout extends LinearLayout {
-    public NotificationLinearLayout(Context context, AttributeSet attrs) {
+    public LatestItemView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
-}
 
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        return onTouchEvent(ev);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
new file mode 100644
index 0000000..7a82267
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2008 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.systemui.statusbar;
+
+import android.app.Notification;
+import android.os.IBinder;
+import android.view.View;
+
+import com.android.internal.statusbar.StatusBarNotification;
+
+import java.util.ArrayList;
+
+/**
+ * The list of currently displaying notifications.
+ */
+public class NotificationData {
+    public static final class Entry {
+        public IBinder key;
+        public StatusBarNotification notification;
+        public StatusBarIconView icon;
+        public View row; // the outer expanded view
+        public View content; // takes the click events and sends the PendingIntent
+        public View expanded; // the inflated RemoteViews
+    }
+    private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
+
+    public int size() {
+        return mEntries.size();
+    }
+
+    public Entry getEntryAt(int index) {
+        return mEntries.get(index);
+    }
+
+    public int findEntry(IBinder key) {
+        final int N = mEntries.size();
+        for (int i=0; i<N; i++) {
+            Entry entry = mEntries.get(i);
+            if (entry.key == key) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    public int add(IBinder key, StatusBarNotification notification, View row, View content,
+            View expanded, StatusBarIconView icon) {
+        Entry entry = new Entry();
+        entry.key = key;
+        entry.notification = notification;
+        entry.row = row;
+        entry.content = content;
+        entry.expanded = expanded;
+        entry.icon = icon;
+        final int index = chooseIndex(notification.notification.when);
+        mEntries.add(index, entry);
+        return index;
+    }
+
+    public Entry remove(IBinder key) {
+        final int N = mEntries.size();
+        for (int i=0; i<N; i++) {
+            Entry entry = mEntries.get(i);
+            if (entry.key == key) {
+                mEntries.remove(i);
+                return entry;
+            }
+        }
+        return null;
+    }
+
+    private int chooseIndex(final long when) {
+        final int N = mEntries.size();
+        for (int i=0; i<N; i++) {
+            Entry entry = mEntries.get(i);
+            if (entry.notification.notification.when > when) {
+                return i;
+            }
+        }
+        return N;
+    }
+
+    /**
+     * Return whether there are any visible items (i.e. items without an error).
+     */
+    public boolean hasVisibleItems() {
+        final int N = mEntries.size();
+        for (int i=0; i<N; i++) {
+            Entry entry = mEntries.get(i);
+            if (entry.expanded != null) { // the view successfully inflated
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Return whether there are any clearable items (that aren't errors).
+     */
+    public boolean hasClearableItems() {
+        final int N = mEntries.size();
+        for (int i=0; i<N; i++) {
+            Entry entry = mEntries.get(i);
+            if (entry.expanded != null) { // the view successfully inflated
+                if ((entry.notification.notification.flags & Notification.FLAG_NO_CLEAR) == 0) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}
diff --git a/services/java/com/android/server/status/NotificationLinearLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLinearLayout.java
similarity index 95%
rename from services/java/com/android/server/status/NotificationLinearLayout.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/NotificationLinearLayout.java
index 2fdf956..8105352 100644
--- a/services/java/com/android/server/status/NotificationLinearLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLinearLayout.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.util.AttributeSet;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
new file mode 100644
index 0000000..e9ae69a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
@@ -0,0 +1,1419 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.statusbar;
+
+import com.android.internal.statusbar.IStatusBar;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarNotification;
+
+import android.app.ActivityManagerNative;
+import android.app.Dialog;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.FrameLayout;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Set;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.StatusBarPolicy;
+
+public class PhoneStatusBarService extends StatusBarService {
+    static final String TAG = "PhoneStatusBarService";
+    static final boolean SPEW = false;
+
+    public static final String ACTION_STATUSBAR_START
+            = "com.android.internal.policy.statusbar.START";
+
+    static final int EXPANDED_LEAVE_ALONE = -10000;
+    static final int EXPANDED_FULL_OPEN = -10001;
+
+    private static final int MSG_ANIMATE = 1000;
+    private static final int MSG_ANIMATE_REVEAL = 1001;
+
+    public interface NotificationCallbacks {
+        void onSetDisabled(int status);
+        void onClearAll();
+        void onNotificationClick(String pkg, String tag, int id);
+        void onPanelRevealed();
+    }
+
+    private class ExpandedDialog extends Dialog {
+        ExpandedDialog(Context context) {
+            super(context, com.android.internal.R.style.Theme_Light_NoTitleBar);
+        }
+
+        @Override
+        public boolean dispatchKeyEvent(KeyEvent event) {
+            boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+            switch (event.getKeyCode()) {
+            case KeyEvent.KEYCODE_BACK:
+                if (!down) {
+                    animateCollapse();
+                }
+                return true;
+            }
+            return super.dispatchKeyEvent(event);
+        }
+    }
+
+    StatusBarPolicy mIconPolicy;
+    
+    int mHeight;
+    int mIconWidth;
+
+    Display mDisplay;
+    StatusBarView mStatusBarView;
+    int mPixelFormat;
+    H mHandler = new H();
+    Object mQueueLock = new Object();
+    
+    // icons
+    String[] mRightIconSlots;
+    LinearLayout mIcons;
+    IconMerger mNotificationIcons;
+    LinearLayout mStatusIcons;
+
+    // expanded notifications
+    Dialog mExpandedDialog;
+    ExpandedView mExpandedView;
+    WindowManager.LayoutParams mExpandedParams;
+    ScrollView mScrollView;
+    View mNotificationLinearLayout;
+    View mExpandedContents;
+    // top bar
+    TextView mNoNotificationsTitle;
+    TextView mClearButton;
+    // drag bar
+    CloseDragHandle mCloseView;
+    // ongoing
+    NotificationData mOngoing = new NotificationData();
+    TextView mOngoingTitle;
+    LinearLayout mOngoingItems;
+    // latest
+    NotificationData mLatest = new NotificationData();
+    TextView mLatestTitle;
+    LinearLayout mLatestItems;
+    // position
+    int[] mPositionTmp = new int[2];
+    boolean mExpanded;
+    boolean mExpandedVisible;
+
+    // the date view
+    DateView mDateView;
+
+    // the tracker view
+    TrackingView mTrackingView;
+    WindowManager.LayoutParams mTrackingParams;
+    int mTrackingPosition; // the position of the top of the tracking view.
+
+    // ticker
+    private Ticker mTicker;
+    private View mTickerView;
+    private boolean mTicking;
+    
+    // Tracking finger for opening/closing.
+    int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
+    boolean mTracking;
+    VelocityTracker mVelocityTracker;
+    
+    static final int ANIM_FRAME_DURATION = (1000/60);
+    
+    boolean mAnimating;
+    long mCurAnimationTime;
+    float mDisplayHeight;
+    float mAnimY;
+    float mAnimVel;
+    float mAnimAccel;
+    long mAnimLastTime;
+    boolean mAnimatingReveal = false;
+    int mViewDelta;
+    int[] mAbsPos = new int[2];
+    
+    // for disabling the status bar
+    int mDisabled = 0;
+
+    /**
+     * Construct the service, add the status bar view to the window manager
+     */
+    @Override
+    public void onCreate() {
+        // First set up our views and stuff.
+        mDisplay = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+        makeStatusBarView(this);
+
+        // Next, call super.onCreate(), which will populate our views.
+        super.onCreate();
+
+        // Lastly, call to the icon policy to install/update all the icons.
+        mIconPolicy = new StatusBarPolicy(this);
+    }
+
+    // ================================================================================
+    // Constructing the view
+    // ================================================================================
+    private void makeStatusBarView(Context context) {
+        Resources res = context.getResources();
+        mRightIconSlots = res.getStringArray(R.array.status_bar_icon_order);
+
+        mHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+        mIconWidth = mHeight;
+
+        ExpandedView expanded = (ExpandedView)View.inflate(context,
+                R.layout.status_bar_expanded, null);
+        expanded.mService = this;
+        StatusBarView sb = (StatusBarView)View.inflate(context, R.layout.status_bar, null);
+        sb.mService = this;
+
+        // figure out which pixel-format to use for the status bar.
+        mPixelFormat = PixelFormat.TRANSLUCENT;
+        Drawable bg = sb.getBackground();
+        if (bg != null) {
+            mPixelFormat = bg.getOpacity();
+        }
+
+        mStatusBarView = sb;
+        mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons);
+        mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons);
+        mIcons = (LinearLayout)sb.findViewById(R.id.icons);
+        mTickerView = sb.findViewById(R.id.ticker);
+        mDateView = (DateView)sb.findViewById(R.id.date);
+
+        mExpandedDialog = new ExpandedDialog(context);
+        mExpandedView = expanded;
+        mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout);
+        mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
+        mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
+        mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
+        mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
+        mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
+        mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
+        mClearButton.setOnClickListener(mClearButtonListener);
+        mScrollView = (ScrollView)expanded.findViewById(R.id.scroll);
+        mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout);
+
+        mOngoingTitle.setVisibility(View.GONE);
+        mLatestTitle.setVisibility(View.GONE);
+        
+        mTicker = new MyTicker(context, sb);
+
+        TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText);
+        tickerView.mTicker = mTicker;
+
+        mTrackingView = (TrackingView)View.inflate(context, R.layout.status_bar_tracking, null);
+        mTrackingView.mService = this;
+        mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close);
+        mCloseView.mService = this;
+
+        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
+
+        // the more notifications icon
+        StatusBarIconView moreView = new StatusBarIconView(this, "more");
+        moreView.set(new StatusBarIcon(null, R.drawable.stat_notify_more, 0));
+        mNotificationIcons.addMoreView(moreView,
+                new LinearLayout.LayoutParams(mIconWidth, mHeight));
+
+        // set the inital view visibility
+        setAreThereNotifications();
+        mDateView.setVisibility(View.INVISIBLE);
+
+        // receive broadcasts
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        context.registerReceiver(mBroadcastReceiver, filter);
+    }
+
+    @Override
+    protected void addStatusBarView() {
+        final StatusBarView view = mStatusBarView;
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                mHeight,
+                WindowManager.LayoutParams.TYPE_STATUS_BAR,
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING,
+                PixelFormat.RGBX_8888);
+        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+        lp.setTitle("StatusBar");
+        // TODO lp.windowAnimations = R.style.Animation_StatusBar;
+
+        WindowManagerImpl.getDefault().addView(view, lp);
+    }
+
+    public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
+        Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
+                + " icon=" + icon);
+        StatusBarIconView view = new StatusBarIconView(this, slot);
+        view.set(icon);
+        mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconWidth, mHeight));
+    }
+
+    public void updateIcon(String slot, int index, int viewIndex,
+            StatusBarIcon old, StatusBarIcon icon) {
+        Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
+                + " old=" + old + " icon=" + icon);
+        StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex);
+        view.set(icon);
+    }
+
+    public void removeIcon(String slot, int index, int viewIndex) {
+        Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
+        mStatusIcons.removeViewAt(viewIndex);
+    }
+
+    public void addNotification(IBinder key, StatusBarNotification notification) {
+        addNotificationViews(key, notification);
+
+        // show the ticker
+        tick(notification);
+
+        // Recalculate the position of the sliding windows and the titles.
+        setAreThereNotifications();
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+    }
+
+    public void updateNotification(IBinder key, StatusBarNotification notification) {
+        Slog.d(TAG, "updateNotification key=" + key + " notification=" + notification);
+
+        NotificationData oldList;
+        int oldIndex = mOngoing.findEntry(key);
+        if (oldIndex >= 0) {
+            oldList = mOngoing;
+        } else {
+            oldIndex = mLatest.findEntry(key);
+            if (oldIndex < 0) {
+                Slog.w(TAG, "updateNotification for unknown key: " + key);
+                return;
+            }
+            oldList = mLatest;
+        }
+        final NotificationData.Entry oldEntry = oldList.getEntryAt(oldIndex);
+        final StatusBarNotification oldNotification = oldEntry.notification;
+        final RemoteViews oldContentView = oldNotification.notification.contentView;
+
+        final RemoteViews contentView = notification.notification.contentView;
+
+        // Can we just reapply the RemoteViews in place?  If when didn't change, the order
+        // didn't change.
+        if (notification.notification.when == oldNotification.notification.when
+                && notification.isOngoing() == oldNotification.isOngoing()
+                && oldEntry.expanded != null
+                && contentView != null && oldContentView != null
+                && contentView.getPackage() != null
+                && oldContentView.getPackage() != null
+                && oldContentView.getPackage().equals(contentView.getPackage())
+                && oldContentView.getLayoutId() == contentView.getLayoutId()) {
+            Slog.d(TAG, "reusing notification");
+            oldEntry.notification = notification;
+            try {
+                // Reapply the RemoteViews
+                contentView.reapply(this, oldEntry.content);
+                // update the contentIntent
+                final PendingIntent contentIntent = notification.notification.contentIntent;
+                if (contentIntent != null) {
+                    oldEntry.content.setOnClickListener(new Launcher(contentIntent,
+                                notification.pkg, notification.tag, notification.id));
+                }
+            }
+            catch (RuntimeException e) {
+                // It failed to add cleanly.  Log, and remove the view from the panel.
+                Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
+                removeNotificationViews(key);
+                addNotificationViews(key, notification);
+            }
+            // Update the icon.
+            oldEntry.icon.set(new StatusBarIcon(notification.pkg, notification.notification.icon,
+                    notification.notification.iconLevel, notification.notification.number));
+        } else {
+            Slog.d(TAG, "not reusing notification");
+            removeNotificationViews(key);
+            addNotificationViews(key, notification);
+        }
+
+        // Restart the ticker if it's still running
+        tick(notification);
+
+        // Recalculate the position of the sliding windows and the titles.
+        setAreThereNotifications();
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+    }
+
+    public void removeNotification(IBinder key) {
+        Slog.d(TAG, "removeNotification key=" + key);
+        StatusBarNotification old = removeNotificationViews(key);
+
+        if (old != null) {
+            // Cancel the ticker if it's still running
+            mTicker.removeEntry(old);
+
+            // Recalculate the position of the sliding windows and the titles.
+            setAreThereNotifications();
+            updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+        }
+    }
+
+    private int chooseIconIndex(boolean isOngoing, int viewIndex) {
+        final int latestSize = mLatest.size();
+        if (isOngoing) {
+            return latestSize + (mOngoing.size() - viewIndex);
+        } else {
+            return latestSize - viewIndex;
+        }
+    }
+
+    View[] makeNotificationView(StatusBarNotification notification, ViewGroup parent) {
+        Notification n = notification.notification;
+        RemoteViews remoteViews = n.contentView;
+        if (remoteViews == null) {
+            return null;
+        }
+
+        // create the row view
+        LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        View row = inflater.inflate(com.android.internal.R.layout.status_bar_latest_event,
+                parent, false);
+
+        // bind the click event to the content area
+        ViewGroup content = (ViewGroup)row.findViewById(com.android.internal.R.id.content);
+        content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+        content.setOnFocusChangeListener(mFocusChangeListener);
+        PendingIntent contentIntent = n.contentIntent;
+        if (contentIntent != null) {
+            content.setOnClickListener(new Launcher(contentIntent, notification.pkg,
+                        notification.tag, notification.id));
+        }
+
+        View expanded = null;
+        Exception exception = null;
+        try {
+            expanded = remoteViews.apply(this, content);
+        }
+        catch (RuntimeException e) {
+            exception = e;
+        }
+        if (expanded == null) {
+            Slog.e(TAG, "couldn't inflate view for package " + notification.pkg, exception);
+            row.setVisibility(View.GONE);
+        } else {
+            content.addView(expanded);
+            row.setDrawingCacheEnabled(true);
+        }
+
+        return new View[] { row, content, expanded };
+    }
+
+    void addNotificationViews(IBinder key, StatusBarNotification notification) {
+        NotificationData list;
+        ViewGroup parent;
+        final boolean isOngoing = notification.isOngoing();
+        if (isOngoing) {
+            list = mOngoing;
+            parent = mOngoingItems;
+        } else {
+            list = mLatest;
+            parent = mLatestItems;
+        }
+        // Construct the expanded view.
+        final View[] views = makeNotificationView(notification, parent);
+        final View row = views[0];
+        final View content = views[1];
+        final View expanded = views[2];
+        // Construct the icon.
+        StatusBarIconView iconView = new StatusBarIconView(this,
+                notification.pkg + "/0x" + Integer.toHexString(notification.id));
+        iconView.set(new StatusBarIcon(notification.pkg, notification.notification.icon,
+                    notification.notification.iconLevel, notification.notification.number));
+        // Add the expanded view.
+        final int viewIndex = list.add(key, notification, row, content, expanded, iconView);
+        parent.addView(row, viewIndex);
+        // Add the icon.
+        final int iconIndex = chooseIconIndex(isOngoing, viewIndex);
+        mNotificationIcons.addView(iconView, iconIndex,
+                new LinearLayout.LayoutParams(mIconWidth, mHeight));
+    }
+
+    StatusBarNotification removeNotificationViews(IBinder key) {
+        NotificationData.Entry entry = mOngoing.remove(key);
+        if (entry == null) {
+            entry = mLatest.remove(key);
+            if (entry == null) {
+                Slog.w(TAG, "removeNotification for unknown key: " + key);
+                return null;
+            }
+        }
+        // Remove the expanded view.
+        ((ViewGroup)entry.row.getParent()).removeView(entry.row);
+        // Remove the icon.
+        ((ViewGroup)entry.icon.getParent()).removeView(entry.icon);
+
+        return entry.notification;
+    }
+
+    private void setAreThereNotifications() {
+        boolean ongoing = mOngoing.hasVisibleItems();
+        boolean latest = mLatest.hasVisibleItems();
+
+        // (no ongoing notifications are clearable)
+        if (mLatest.hasClearableItems()) {
+            mClearButton.setVisibility(View.VISIBLE);
+        } else {
+            mClearButton.setVisibility(View.INVISIBLE);
+        }
+
+        mOngoingTitle.setVisibility(ongoing ? View.VISIBLE : View.GONE);
+        mLatestTitle.setVisibility(latest ? View.VISIBLE : View.GONE);
+
+        if (ongoing || latest) {
+            mNoNotificationsTitle.setVisibility(View.GONE);
+        } else {
+            mNoNotificationsTitle.setVisibility(View.VISIBLE);
+        }
+    }
+
+
+    /**
+     * State is one or more of the DISABLE constants from StatusBarManager.
+     */
+    public void disable(int state) {
+        final int old = mDisabled;
+        final int diff = state ^ old;
+        mDisabled = state;
+
+        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
+            if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
+                Slog.d(TAG, "DISABLE_EXPAND: yes");
+                animateCollapse();
+            }
+        }
+        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+            if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+                if (mTicking) {
+                    mTicker.halt();
+                } else {
+                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
+                }
+            } else {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+                if (!mExpandedVisible) {
+                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+                }
+            }
+        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+            if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes");
+                mTicker.halt();
+            }
+        }
+    }
+
+    /**
+     * All changes to the status bar and notifications funnel through here and are batched.
+     */
+    private class H extends Handler {
+        public void handleMessage(Message m) {
+            switch (m.what) {
+                case MSG_ANIMATE:
+                    doAnimation();
+                    break;
+                case MSG_ANIMATE_REVEAL:
+                    doRevealAnimation();
+                    break;
+            }
+        }
+    }
+
+    View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
+        public void onFocusChange(View v, boolean hasFocus) {
+            // Because 'v' is a ViewGroup, all its children will be (un)selected
+            // too, which allows marqueeing to work.
+            v.setSelected(hasFocus);
+        }
+    };
+
+    private void makeExpandedVisible() {
+        if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
+        if (mExpandedVisible) {
+            return;
+        }
+        mExpandedVisible = true;
+        visibilityChanged(true);
+        
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+        mExpandedView.requestFocus(View.FOCUS_FORWARD);
+        mTrackingView.setVisibility(View.VISIBLE);
+        
+        if (!mTicking) {
+            setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
+        }
+    }
+    
+    public void animateExpand() {
+        if (SPEW) Slog.d(TAG, "Animate expand: expanded=" + mExpanded);
+        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+            return ;
+        }
+        if (mExpanded) {
+            return;
+        }
+
+        prepareTracking(0, true);
+        performFling(0, 2000.0f, true);
+    }
+    
+    public void animateCollapse() {
+        if (SPEW) {
+            Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
+                    + " mExpandedVisible=" + mExpandedVisible
+                    + " mExpanded=" + mExpanded
+                    + " mAnimating=" + mAnimating
+                    + " mAnimY=" + mAnimY
+                    + " mAnimVel=" + mAnimVel);
+        }
+        
+        if (!mExpandedVisible) {
+            return;
+        }
+
+        int y;
+        if (mAnimating) {
+            y = (int)mAnimY;
+        } else {
+            y = mDisplay.getHeight()-1;
+        }
+        // Let the fling think that we're open so it goes in the right direction
+        // and doesn't try to re-open the windowshade.
+        mExpanded = true;
+        prepareTracking(y, false);
+        performFling(y, -2000.0f, true);
+    }
+    
+    void performExpand() {
+        if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded);
+        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+            return ;
+        }
+        if (mExpanded) {
+            return;
+        }
+
+        mExpanded = true;
+        makeExpandedVisible();
+        updateExpandedViewPos(EXPANDED_FULL_OPEN);
+
+        if (false) postStartTracing();
+    }
+
+    void performCollapse() {
+        if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded
+                + " mExpandedVisible=" + mExpandedVisible);
+        
+        if (!mExpandedVisible) {
+            return;
+        }
+        mExpandedVisible = false;
+        visibilityChanged(false);
+        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+        mTrackingView.setVisibility(View.GONE);
+
+        if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
+            setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+        }
+        setDateViewVisibility(false, com.android.internal.R.anim.fade_out);
+        
+        if (!mExpanded) {
+            return;
+        }
+        mExpanded = false;
+    }
+
+    void doAnimation() {
+        if (mAnimating) {
+            if (SPEW) Slog.d(TAG, "doAnimation");
+            if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
+            incrementAnim();
+            if (SPEW) Slog.d(TAG, "doAnimation after  mAnimY=" + mAnimY);
+            if (mAnimY >= mDisplay.getHeight()-1) {
+                if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
+                mAnimating = false;
+                updateExpandedViewPos(EXPANDED_FULL_OPEN);
+                performExpand();
+            }
+            else if (mAnimY < mStatusBarView.getHeight()) {
+                if (SPEW) Slog.d(TAG, "Animation completed to collapsed state.");
+                mAnimating = false;
+                updateExpandedViewPos(0);
+                performCollapse();
+            }
+            else {
+                updateExpandedViewPos((int)mAnimY);
+                mCurAnimationTime += ANIM_FRAME_DURATION;
+                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
+            }
+        }
+    }
+
+    void stopTracking() {
+        mTracking = false;
+        mVelocityTracker.recycle();
+        mVelocityTracker = null;
+    }
+
+    void incrementAnim() {
+        long now = SystemClock.uptimeMillis();
+        float t = ((float)(now - mAnimLastTime)) / 1000;            // ms -> s
+        final float y = mAnimY;
+        final float v = mAnimVel;                                   // px/s
+        final float a = mAnimAccel;                                 // px/s/s
+        mAnimY = y + (v*t) + (0.5f*a*t*t);                          // px
+        mAnimVel = v + (a*t);                                       // px/s
+        mAnimLastTime = now;                                        // ms
+        //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY
+        //        + " mAnimAccel=" + mAnimAccel);
+    }
+
+    void doRevealAnimation() {
+        final int h = mCloseView.getHeight() + mStatusBarView.getHeight();
+        if (mAnimatingReveal && mAnimating && mAnimY < h) {
+            incrementAnim();
+            if (mAnimY >= h) {
+                mAnimY = h;
+                updateExpandedViewPos((int)mAnimY);
+            } else {
+                updateExpandedViewPos((int)mAnimY);
+                mCurAnimationTime += ANIM_FRAME_DURATION;
+                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
+                        mCurAnimationTime);
+            }
+        }
+    }
+    
+    void prepareTracking(int y, boolean opening) {
+        mTracking = true;
+        mVelocityTracker = VelocityTracker.obtain();
+        if (opening) {
+            mAnimAccel = 2000.0f;
+            mAnimVel = 200;
+            mAnimY = mStatusBarView.getHeight();
+            updateExpandedViewPos((int)mAnimY);
+            mAnimating = true;
+            mAnimatingReveal = true;
+            mHandler.removeMessages(MSG_ANIMATE);
+            mHandler.removeMessages(MSG_ANIMATE_REVEAL);
+            long now = SystemClock.uptimeMillis();
+            mAnimLastTime = now;
+            mCurAnimationTime = now + ANIM_FRAME_DURATION;
+            mAnimating = true;
+            mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
+                    mCurAnimationTime);
+            makeExpandedVisible();
+        } else {
+            // it's open, close it?
+            if (mAnimating) {
+                mAnimating = false;
+                mHandler.removeMessages(MSG_ANIMATE);
+            }
+            updateExpandedViewPos(y + mViewDelta);
+        }
+    }
+    
+    void performFling(int y, float vel, boolean always) {
+        mAnimatingReveal = false;
+        mDisplayHeight = mDisplay.getHeight();
+
+        mAnimY = y;
+        mAnimVel = vel;
+
+        //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel);
+
+        if (mExpanded) {
+            if (!always && (
+                    vel > 200.0f
+                    || (y > (mDisplayHeight-25) && vel > -200.0f))) {
+                // We are expanded, but they didn't move sufficiently to cause
+                // us to retract.  Animate back to the expanded position.
+                mAnimAccel = 2000.0f;
+                if (vel < 0) {
+                    mAnimVel = 0;
+                }
+            }
+            else {
+                // We are expanded and are now going to animate away.
+                mAnimAccel = -2000.0f;
+                if (vel > 0) {
+                    mAnimVel = 0;
+                }
+            }
+        } else {
+            if (always || (
+                    vel > 200.0f
+                    || (y > (mDisplayHeight/2) && vel > -200.0f))) {
+                // We are collapsed, and they moved enough to allow us to
+                // expand.  Animate in the notifications.
+                mAnimAccel = 2000.0f;
+                if (vel < 0) {
+                    mAnimVel = 0;
+                }
+            }
+            else {
+                // We are collapsed, but they didn't move sufficiently to cause
+                // us to retract.  Animate back to the collapsed position.
+                mAnimAccel = -2000.0f;
+                if (vel > 0) {
+                    mAnimVel = 0;
+                }
+            }
+        }
+        //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
+        //        + " mAnimAccel=" + mAnimAccel);
+
+        long now = SystemClock.uptimeMillis();
+        mAnimLastTime = now;
+        mCurAnimationTime = now + ANIM_FRAME_DURATION;
+        mAnimating = true;
+        mHandler.removeMessages(MSG_ANIMATE);
+        mHandler.removeMessages(MSG_ANIMATE_REVEAL);
+        mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
+        stopTracking();
+    }
+    
+    boolean interceptTouchEvent(MotionEvent event) {
+        if (SPEW) {
+            Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
+                + mDisabled);
+        }
+
+        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
+            return false;
+        }
+        
+        final int statusBarSize = mStatusBarView.getHeight();
+        final int hitSize = statusBarSize*2;
+        if (event.getAction() == MotionEvent.ACTION_DOWN) {
+            final int y = (int)event.getRawY();
+
+            if (!mExpanded) {
+                mViewDelta = statusBarSize - y;
+            } else {
+                mTrackingView.getLocationOnScreen(mAbsPos);
+                mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y;
+            }
+            if ((!mExpanded && y < hitSize) ||
+                    (mExpanded && y > (mDisplay.getHeight()-hitSize))) {
+
+                // We drop events at the edge of the screen to make the windowshade come
+                // down by accident less, especially when pushing open a device with a keyboard
+                // that rotates (like g1 and droid)
+                int x = (int)event.getRawX();
+                final int edgeBorder = mEdgeBorder;
+                if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) {
+                    prepareTracking(y, !mExpanded);// opening if we're not already fully visible
+                    mVelocityTracker.addMovement(event);
+                }
+            }
+        } else if (mTracking) {
+            mVelocityTracker.addMovement(event);
+            final int minY = statusBarSize + mCloseView.getHeight();
+            if (event.getAction() == MotionEvent.ACTION_MOVE) {
+                int y = (int)event.getRawY();
+                if (mAnimatingReveal && y < minY) {
+                    // nothing
+                } else  {
+                    mAnimatingReveal = false;
+                    updateExpandedViewPos(y + mViewDelta);
+                }
+            } else if (event.getAction() == MotionEvent.ACTION_UP) {
+                mVelocityTracker.computeCurrentVelocity(1000);
+
+                float yVel = mVelocityTracker.getYVelocity();
+                boolean negative = yVel < 0;
+
+                float xVel = mVelocityTracker.getXVelocity();
+                if (xVel < 0) {
+                    xVel = -xVel;
+                }
+                if (xVel > 150.0f) {
+                    xVel = 150.0f; // limit how much we care about the x axis
+                }
+
+                float vel = (float)Math.hypot(yVel, xVel);
+                if (negative) {
+                    vel = -vel;
+                }
+                
+                performFling((int)event.getRawY(), vel, false);
+            }
+            
+        }
+        return false;
+    }
+
+    private class Launcher implements View.OnClickListener {
+        private PendingIntent mIntent;
+        private String mPkg;
+        private String mTag;
+        private int mId;
+
+        Launcher(PendingIntent intent, String pkg, String tag, int id) {
+            mIntent = intent;
+            mPkg = pkg;
+            mTag = tag;
+            mId = id;
+        }
+
+        public void onClick(View v) {
+            try {
+                // The intent we are sending is for the application, which
+                // won't have permission to immediately start an activity after
+                // the user switches to home.  We know it is safe to do at this
+                // point, so make sure new activity switches are now allowed.
+                ActivityManagerNative.getDefault().resumeAppSwitches();
+            } catch (RemoteException e) {
+            }
+            int[] pos = new int[2];
+            v.getLocationOnScreen(pos);
+            Intent overlay = new Intent();
+            overlay.setSourceBounds(
+                    new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
+            try {
+                mIntent.send(PhoneStatusBarService.this, 0, overlay);
+            } catch (PendingIntent.CanceledException e) {
+                // the stack trace isn't very helpful here.  Just log the exception message.
+                Slog.w(TAG, "Sending contentIntent failed: " + e);
+            }
+            try {
+                mBarService.onNotificationClick(mPkg, mTag, mId);
+            } catch (RemoteException ex) {
+                // system process is dead if we're here.
+            }
+            animateCollapse();
+        }
+    }
+
+    private void tick(StatusBarNotification n) {
+        // Show the ticker if one is requested. Also don't do this
+        // until status bar window is attached to the window manager,
+        // because...  well, what's the point otherwise?  And trying to
+        // run a ticker without being attached will crash!
+        if (n.notification.tickerText != null && mStatusBarView.getWindowToken() != null) {
+            if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
+                            | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
+                mTicker.addEntry(n);
+            }
+        }
+    }
+
+    private class MyTicker extends Ticker {
+        MyTicker(Context context, StatusBarView sb) {
+            super(context, sb);
+        }
+        
+        @Override
+        void tickerStarting() {
+            mTicking = true;
+            mIcons.setVisibility(View.GONE);
+            mTickerView.setVisibility(View.VISIBLE);
+            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));
+            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
+            if (mExpandedVisible) {
+                setDateViewVisibility(false, com.android.internal.R.anim.push_up_out);
+            }
+        }
+
+        @Override
+        void tickerDone() {
+            mIcons.setVisibility(View.VISIBLE);
+            mTickerView.setVisibility(View.GONE);
+            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
+            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out,
+                        mTickingDoneListener));
+            if (mExpandedVisible) {
+                setDateViewVisibility(true, com.android.internal.R.anim.push_down_in);
+            }
+        }
+
+        void tickerHalting() {
+            mIcons.setVisibility(View.VISIBLE);
+            mTickerView.setVisibility(View.GONE);
+            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
+            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out,
+                        mTickingDoneListener));
+            if (mExpandedVisible) {
+                setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
+            }
+        }
+    }
+
+    Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {;
+        public void onAnimationEnd(Animation animation) {
+            mTicking = false;
+        }
+        public void onAnimationRepeat(Animation animation) {
+        }
+        public void onAnimationStart(Animation animation) {
+        }
+    };
+
+    private Animation loadAnim(int id, Animation.AnimationListener listener) {
+        Animation anim = AnimationUtils.loadAnimation(PhoneStatusBarService.this, id);
+        if (listener != null) {
+            anim.setAnimationListener(listener);
+        }
+        return anim;
+    }
+
+    public String viewInfo(View v) {
+        return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
+                + " " + v.getWidth() + "x" + v.getHeight() + ")";
+    }
+
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump StatusBar from from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid());
+            return;
+        }
+        
+        synchronized (mQueueLock) {
+            pw.println("Current Status Bar state:");
+            pw.println("  mExpanded=" + mExpanded
+                    + ", mExpandedVisible=" + mExpandedVisible);
+            pw.println("  mTicking=" + mTicking);
+            pw.println("  mTracking=" + mTracking);
+            pw.println("  mAnimating=" + mAnimating
+                    + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel
+                    + ", mAnimAccel=" + mAnimAccel);
+            pw.println("  mCurAnimationTime=" + mCurAnimationTime
+                    + " mAnimLastTime=" + mAnimLastTime);
+            pw.println("  mDisplayHeight=" + mDisplayHeight
+                    + " mAnimatingReveal=" + mAnimatingReveal
+                    + " mViewDelta=" + mViewDelta);
+            pw.println("  mDisplayHeight=" + mDisplayHeight);
+            pw.println("  mExpandedParams: " + mExpandedParams);
+            pw.println("  mExpandedView: " + viewInfo(mExpandedView));
+            pw.println("  mExpandedDialog: " + mExpandedDialog);
+            pw.println("  mTrackingParams: " + mTrackingParams);
+            pw.println("  mTrackingView: " + viewInfo(mTrackingView));
+            pw.println("  mOngoingTitle: " + viewInfo(mOngoingTitle));
+            pw.println("  mOngoingItems: " + viewInfo(mOngoingItems));
+            pw.println("  mLatestTitle: " + viewInfo(mLatestTitle));
+            pw.println("  mLatestItems: " + viewInfo(mLatestItems));
+            pw.println("  mNoNotificationsTitle: " + viewInfo(mNoNotificationsTitle));
+            pw.println("  mCloseView: " + viewInfo(mCloseView));
+            pw.println("  mTickerView: " + viewInfo(mTickerView));
+            pw.println("  mScrollView: " + viewInfo(mScrollView)
+                    + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
+            pw.println("mNotificationLinearLayout: " + viewInfo(mNotificationLinearLayout));
+        }
+        /*
+        synchronized (mNotificationData) {
+            int N = mNotificationData.ongoingCount();
+            pw.println("  ongoingCount.size=" + N);
+            for (int i=0; i<N; i++) {
+                StatusBarNotification n = mNotificationData.getOngoing(i);
+                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
+                pw.println("           data=" + n.data);
+            }
+            N = mNotificationData.latestCount();
+            pw.println("  ongoingCount.size=" + N);
+            for (int i=0; i<N; i++) {
+                StatusBarNotification n = mNotificationData.getLatest(i);
+                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
+                pw.println("           data=" + n.data);
+            }
+        }
+        */
+        
+        if (false) {
+            pw.println("see the logcat for a dump of the views we have created.");
+            // must happen on ui thread
+            mHandler.post(new Runnable() {
+                    public void run() {
+                        mStatusBarView.getLocationOnScreen(mAbsPos);
+                        Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                                + ") " + mStatusBarView.getWidth() + "x"
+                                + mStatusBarView.getHeight());
+                        mStatusBarView.debug();
+
+                        mExpandedView.getLocationOnScreen(mAbsPos);
+                        Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                                + ") " + mExpandedView.getWidth() + "x"
+                                + mExpandedView.getHeight());
+                        mExpandedView.debug();
+
+                        mTrackingView.getLocationOnScreen(mAbsPos);
+                        Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+                                + ") " + mTrackingView.getWidth() + "x"
+                                + mTrackingView.getHeight());
+                        mTrackingView.debug();
+                    }
+                });
+        }
+    }
+
+    void onBarViewAttached() {
+        WindowManager.LayoutParams lp;
+        int pixelFormat;
+        Drawable bg;
+
+        /// ---------- Tracking View --------------
+        pixelFormat = PixelFormat.RGBX_8888;
+        bg = mTrackingView.getBackground();
+        if (bg != null) {
+            pixelFormat = bg.getOpacity();
+        }
+
+        lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+                pixelFormat);
+//        lp.token = mStatusBarView.getWindowToken();
+        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+        lp.setTitle("TrackingView");
+        lp.y = mTrackingPosition;
+        mTrackingParams = lp;
+
+        WindowManagerImpl.getDefault().addView(mTrackingView, lp);
+    }
+
+    void onTrackingViewAttached() {
+        WindowManager.LayoutParams lp;
+        int pixelFormat;
+        Drawable bg;
+
+        /// ---------- Expanded View --------------
+        pixelFormat = PixelFormat.TRANSLUCENT;
+
+        final int disph = mDisplay.getHeight();
+        lp = mExpandedDialog.getWindow().getAttributes();
+        lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
+        lp.height = getExpandedHeight();
+        lp.x = 0;
+        mTrackingPosition = lp.y = -disph; // sufficiently large negative
+        lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+        lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | WindowManager.LayoutParams.FLAG_DITHER
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        lp.format = pixelFormat;
+        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+        lp.setTitle("StatusBarExpanded");
+        mExpandedDialog.getWindow().setAttributes(lp);
+        mExpandedDialog.getWindow().setFormat(pixelFormat);
+        mExpandedParams = lp;
+
+        mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+        mExpandedDialog.setContentView(mExpandedView,
+                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                                           ViewGroup.LayoutParams.MATCH_PARENT));
+        mExpandedDialog.getWindow().setBackgroundDrawable(null);
+        mExpandedDialog.show();
+        FrameLayout hack = (FrameLayout)mExpandedView.getParent();
+    }
+
+    void setDateViewVisibility(boolean visible, int anim) {
+        mDateView.setUpdates(visible);
+        mDateView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+        mDateView.startAnimation(loadAnim(anim, null));
+    }
+
+    void setNotificationIconVisibility(boolean visible, int anim) {
+        int old = mNotificationIcons.getVisibility();
+        int v = visible ? View.VISIBLE : View.INVISIBLE;
+        if (old != v) {
+            mNotificationIcons.setVisibility(v);
+            mNotificationIcons.startAnimation(loadAnim(anim, null));
+        }
+    }
+
+    void updateExpandedViewPos(int expandedPosition) {
+        if (SPEW) {
+            Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
+                    + " mTrackingParams.y=" + mTrackingParams.y
+                    + " mTrackingPosition=" + mTrackingPosition);
+        }
+
+        int h = mStatusBarView.getHeight();
+        int disph = mDisplay.getHeight();
+
+        // If the expanded view is not visible, make sure they're still off screen.
+        // Maybe the view was resized.
+        if (!mExpandedVisible) {
+            if (mTrackingView != null) {
+                mTrackingPosition = -disph;
+                if (mTrackingParams != null) {
+                    mTrackingParams.y = mTrackingPosition;
+                    WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
+                }
+            }
+            if (mExpandedParams != null) {
+                mExpandedParams.y = -disph;
+                mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+            }
+            return;
+        }
+
+        // tracking view...
+        int pos;
+        if (expandedPosition == EXPANDED_FULL_OPEN) {
+            pos = h;
+        }
+        else if (expandedPosition == EXPANDED_LEAVE_ALONE) {
+            pos = mTrackingPosition;
+        }
+        else {
+            if (expandedPosition <= disph) {
+                pos = expandedPosition;
+            } else {
+                pos = disph;
+            }
+            pos -= disph-h;
+        }
+        mTrackingPosition = mTrackingParams.y = pos;
+        mTrackingParams.height = disph-h;
+        WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
+
+        if (mExpandedParams != null) {
+            mCloseView.getLocationInWindow(mPositionTmp);
+            final int closePos = mPositionTmp[1];
+
+            mExpandedContents.getLocationInWindow(mPositionTmp);
+            final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
+
+            mExpandedParams.y = pos + mTrackingView.getHeight()
+                    - (mTrackingParams.height-closePos) - contentsBottom;
+            int max = h;
+            if (mExpandedParams.y > max) {
+                mExpandedParams.y = max;
+            }
+            int min = mTrackingPosition;
+            if (mExpandedParams.y < min) {
+                mExpandedParams.y = min;
+            }
+
+            boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h;
+            if (!visible) {
+                // if the contents aren't visible, move the expanded view way off screen
+                // because the window itself extends below the content view.
+                mExpandedParams.y = -disph;
+            }
+            visibilityChanged(visible);
+            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+        }
+
+        if (SPEW) {
+            Slog.d(TAG, "updateExpandedViewPos after  expandedPosition=" + expandedPosition
+                    + " mTrackingParams.y=" + mTrackingParams.y
+                    + " mTrackingPosition=" + mTrackingPosition
+                    + " mExpandedParams.y=" + mExpandedParams.y
+                    + " mExpandedParams.height=" + mExpandedParams.height);
+        }
+    }
+
+    int getExpandedHeight() {
+        return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight();
+    }
+
+    void updateExpandedHeight() {
+        if (mExpandedView != null) {
+            mExpandedParams.height = getExpandedHeight();
+            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+        }
+    }
+
+    /**
+     * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
+     * This was added last-minute and is inconsistent with the way the rest of the notifications
+     * are handled, because the notification isn't really cancelled.  The lights are just
+     * turned off.  If any other notifications happen, the lights will turn back on.  Steve says
+     * this is what he wants. (see bug 1131461)
+     */
+    private boolean mPanelSlightlyVisible;
+    void visibilityChanged(boolean visible) {
+        if (mPanelSlightlyVisible != visible) {
+            mPanelSlightlyVisible = visible;
+            try {
+                mBarService.visibilityChanged(visible);
+            } catch (RemoteException ex) {
+                // Won't fail unless the world has ended.
+            }
+        }
+    }
+
+    void performDisableActions(int net) {
+        int old = mDisabled;
+        int diff = net ^ old;
+        mDisabled = net;
+
+        // act accordingly
+        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
+            if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
+                Slog.d(TAG, "DISABLE_EXPAND: yes");
+                animateCollapse();
+            }
+        }
+        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+            if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+                if (mTicking) {
+                    mNotificationIcons.setVisibility(View.INVISIBLE);
+                    mTicker.halt();
+                } else {
+                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
+                }
+            } else {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+                if (!mExpandedVisible) {
+                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+                }
+            }
+        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+            if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+                mTicker.halt();
+            }
+        }
+    }
+
+    private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            try {
+                mBarService.onClearAllNotifications();
+            } catch (RemoteException ex) {
+                // system process is dead if we're here.
+            }
+            animateCollapse();
+        }
+    };
+
+    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
+                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
+                //collapse();
+            }
+            else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+                updateResources();
+            }
+        }
+    };
+
+    /**
+     * Reload some of our resources when the configuration changes.
+     * 
+     * We don't reload everything when the configuration changes -- we probably
+     * should, but getting that smooth is tough.  Someday we'll fix that.  In the
+     * meantime, just update the things that we know change.
+     */
+    void updateResources() {
+        Resources res = getResources();
+
+        mClearButton.setText(getText(R.string.status_bar_clear_all_button));
+        mOngoingTitle.setText(getText(R.string.status_bar_ongoing_events_title));
+        mLatestTitle.setText(getText(R.string.status_bar_latest_events_title));
+        mNoNotificationsTitle.setText(getText(R.string.status_bar_no_notifications_title));
+
+        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
+
+        if (false) Slog.v(TAG, "updateResources");
+    }
+
+    //
+    // tracing
+    //
+
+    void postStartTracing() {
+        mHandler.postDelayed(mStartTracing, 3000);
+    }
+
+    void vibrate() {
+        android.os.Vibrator vib = (android.os.Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
+        vib.vibrate(250);
+    }
+
+    Runnable mStartTracing = new Runnable() {
+        public void run() {
+            vibrate();
+            SystemClock.sleep(250);
+            Slog.d(TAG, "startTracing");
+            android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
+            mHandler.postDelayed(mStopTracing, 10000);
+        }
+    };
+
+    Runnable mStopTracing = new Runnable() {
+        public void run() {
+            android.os.Debug.stopMethodTracing();
+            Slog.d(TAG, "stopTracing");
+            vibrate();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
new file mode 100644
index 0000000..5eb0d683
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2008 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.systemui.statusbar;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.graphics.Canvas;
+import android.util.Slog;
+import android.view.ViewDebug;
+import android.widget.FrameLayout;
+
+import com.android.internal.statusbar.StatusBarIcon;
+
+public class StatusBarIconView extends AnimatedImageView {
+    private static final String TAG = "StatusBarIconView";
+
+    private StatusBarIcon mIcon;
+    @ViewDebug.ExportedProperty private String mSlot;
+    @ViewDebug.ExportedProperty private boolean mError;
+
+    public StatusBarIconView(Context context, String slot) {
+        super(context);
+        mSlot = slot;
+    }
+
+    private static boolean streq(String a, String b) {
+        if (a == b) {
+            return true;
+        }
+        if (a == null && b != null) {
+            return false;
+        }
+        if (a != null && b == null) {
+            return false;
+        }
+        return a.equals(b);
+    }
+
+    public void set(StatusBarIcon icon) {
+        error: {
+            final boolean iconEquals = !mError
+                    && mIcon != null
+                    && streq(mIcon.iconPackage, icon.iconPackage)
+                    && mIcon.iconId == icon.iconId;
+            final boolean levelEquals = !mError
+                    && iconEquals
+                    && mIcon.iconLevel == icon.iconLevel;
+            final boolean visibilityEquals = !mError
+                    && mIcon != null
+                    && mIcon.visible == icon.visible;
+            mError = false;
+            if (!iconEquals) {
+                Drawable drawable = getIcon(icon);
+                if (drawable == null) {
+                    mError = true;
+                    Slog.w(PhoneStatusBarService.TAG, "No icon ID for slot " + mSlot);
+                    break error;
+                }
+                setImageDrawable(drawable);
+            }
+            if (!levelEquals) {
+                setImageLevel(icon.iconLevel);
+            }
+            if (!visibilityEquals) {
+                setVisibility(icon.visible ? VISIBLE : GONE);
+            }
+            mIcon = icon.clone();
+        }
+        if (mError) {
+            setVisibility(GONE);
+        }
+    }
+
+    private Drawable getIcon(StatusBarIcon icon) {
+        return getIcon(getContext(), icon);
+    }
+
+    /**
+     * Returns the right icon to use for this item, respecting the iconId and
+     * iconPackage (if set)
+     * 
+     * @param context Context to use to get resources if iconPackage is not set
+     * @return Drawable for this item, or null if the package or item could not
+     *         be found
+     */
+    public static Drawable getIcon(Context context, StatusBarIcon icon) {
+        Resources r = null;
+
+        if (icon.iconPackage != null) {
+            try {
+                r = context.getPackageManager().getResourcesForApplication(icon.iconPackage);
+            } catch (PackageManager.NameNotFoundException ex) {
+                Slog.e(PhoneStatusBarService.TAG, "Icon package not found: "+icon.iconPackage, ex);
+                return null;
+            }
+        } else {
+            r = context.getResources();
+        }
+
+        if (icon.iconId == 0) {
+            return null;
+        }
+        
+        try {
+            return r.getDrawable(icon.iconId);
+        } catch (RuntimeException e) {
+            Slog.w(PhoneStatusBarService.TAG, "Icon not found in "
+                  + (icon.iconPackage != null ? icon.iconId : "<system>")
+                  + ": " + Integer.toHexString(icon.iconId));
+        }
+
+        return null;
+    }
+
+    public StatusBarIcon getStatusBarIcon() {
+        return mIcon;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
new file mode 100644
index 0000000..9ef9d0d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
@@ -0,0 +1,1160 @@
+/*
+ * Copyright (C) 2008 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.systemui.statusbar.policy;
+
+import android.app.StatusBarManager;
+import android.app.AlertDialog;
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothPbap;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.TypedArray;
+import android.graphics.PixelFormat;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.location.LocationManager;
+import android.media.AudioManager;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.NetworkInfo;
+import android.net.Uri;
+import android.net.wifi.WifiManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.storage.StorageManager;
+import android.provider.Settings;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
+import android.text.format.DateFormat;
+import android.text.style.CharacterStyle;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.StyleSpan;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.util.Slog;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.cdma.EriInfo;
+import com.android.internal.telephony.cdma.TtyIntent;
+import com.android.server.am.BatteryStatsService;
+
+import com.android.systemui.R;
+
+/**
+ * This class contains all of the policy about which icons are installed in the status
+ * bar at boot time.  It goes through the normal API for icons, even though it probably
+ * strictly doesn't need to.
+ */
+public class StatusBarPolicy {
+    private static final String TAG = "StatusBarPolicy";
+
+    // message codes for the handler
+    private static final int EVENT_BATTERY_CLOSE = 4;
+
+    private static final int AM_PM_STYLE_NORMAL  = 0;
+    private static final int AM_PM_STYLE_SMALL   = 1;
+    private static final int AM_PM_STYLE_GONE    = 2;
+
+    private static final int AM_PM_STYLE = AM_PM_STYLE_GONE;
+
+    private final Context mContext;
+    private final StatusBarManager mService;
+    private final Handler mHandler = new StatusBarHandler();
+    private final IBatteryStats mBatteryStats;
+
+    // storage
+    private StorageManager mStorageManager;
+
+    // battery
+    private boolean mBatteryFirst = true;
+    private boolean mBatteryPlugged;
+    private int mBatteryLevel;
+    private AlertDialog mLowBatteryDialog;
+    private TextView mBatteryLevelTextView;
+    private View mBatteryView;
+    private int mBatteryViewSequence;
+    private boolean mBatteryShowLowOnEndCall = false;
+    private static final boolean SHOW_LOW_BATTERY_WARNING = true;
+    private static final boolean SHOW_BATTERY_WARNINGS_IN_CALL = true;
+
+    // phone
+    private TelephonyManager mPhone;
+    private int mPhoneSignalIconId;
+
+    //***** Signal strength icons
+    //GSM/UMTS
+    private static final int[] sSignalImages = new int[] {
+        R.drawable.stat_sys_signal_0,
+        R.drawable.stat_sys_signal_1,
+        R.drawable.stat_sys_signal_2,
+        R.drawable.stat_sys_signal_3,
+        R.drawable.stat_sys_signal_4
+    };
+    private static final int[] sSignalImages_r = new int[] {
+        R.drawable.stat_sys_r_signal_0,
+        R.drawable.stat_sys_r_signal_1,
+        R.drawable.stat_sys_r_signal_2,
+        R.drawable.stat_sys_r_signal_3,
+        R.drawable.stat_sys_r_signal_4
+    };
+    private static final int[] sRoamingIndicatorImages_cdma = new int[] {
+        R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator
+        // 1 is Standard Roaming Indicator OFF
+        // TODO T: image never used, remove and put 0 instead?
+        R.drawable.stat_sys_roaming_cdma_0,
+
+        // 2 is Standard Roaming Indicator FLASHING
+        // TODO T: image never used, remove and put 0 instead?
+        R.drawable.stat_sys_roaming_cdma_0,
+
+        // 3-12 Standard ERI
+        R.drawable.stat_sys_roaming_cdma_0, //3
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+
+        // 13-63 Reserved for Standard ERI
+        R.drawable.stat_sys_roaming_cdma_0, //13
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+
+        // 64-127 Reserved for Non Standard (Operator Specific) ERI
+        R.drawable.stat_sys_roaming_cdma_0, //64
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0,
+        R.drawable.stat_sys_roaming_cdma_0 //83
+
+        // 128-255 Reserved
+    };
+
+    //***** Data connection icons
+    private int[] mDataIconList = sDataNetType_g;
+    //GSM/UMTS
+    private static final int[] sDataNetType_g = new int[] {
+            R.drawable.stat_sys_data_connected_g,
+            R.drawable.stat_sys_data_in_g,
+            R.drawable.stat_sys_data_out_g,
+            R.drawable.stat_sys_data_inandout_g,
+        };
+    private static final int[] sDataNetType_3g = new int[] {
+            R.drawable.stat_sys_data_connected_3g,
+            R.drawable.stat_sys_data_in_3g,
+            R.drawable.stat_sys_data_out_3g,
+            R.drawable.stat_sys_data_inandout_3g,
+        };
+    private static final int[] sDataNetType_e = new int[] {
+            R.drawable.stat_sys_data_connected_e,
+            R.drawable.stat_sys_data_in_e,
+            R.drawable.stat_sys_data_out_e,
+            R.drawable.stat_sys_data_inandout_e,
+        };
+    //3.5G
+    private static final int[] sDataNetType_h = new int[] {
+            R.drawable.stat_sys_data_connected_h,
+            R.drawable.stat_sys_data_in_h,
+            R.drawable.stat_sys_data_out_h,
+            R.drawable.stat_sys_data_inandout_h,
+    };
+
+    //CDMA
+    // Use 3G icons for EVDO data and 1x icons for 1XRTT data
+    private static final int[] sDataNetType_1x = new int[] {
+        R.drawable.stat_sys_data_connected_1x,
+        R.drawable.stat_sys_data_in_1x,
+        R.drawable.stat_sys_data_out_1x,
+        R.drawable.stat_sys_data_inandout_1x,
+    };
+
+    // Assume it's all good unless we hear otherwise.  We don't always seem
+    // to get broadcasts that it *is* there.
+    IccCard.State mSimState = IccCard.State.READY;
+    int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
+    int mDataState = TelephonyManager.DATA_DISCONNECTED;
+    int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
+    ServiceState mServiceState;
+    SignalStrength mSignalStrength;
+
+    // data connection
+    private boolean mDataIconVisible;
+    private boolean mHspaDataDistinguishable;
+
+    // ringer volume
+    private boolean mVolumeVisible;
+
+    // bluetooth device status
+    private int mBluetoothHeadsetState;
+    private boolean mBluetoothA2dpConnected;
+    private int mBluetoothPbapState;
+    private boolean mBluetoothEnabled;
+
+    // wifi
+    private static final int[] sWifiSignalImages = new int[] {
+            R.drawable.stat_sys_wifi_signal_1,
+            R.drawable.stat_sys_wifi_signal_2,
+            R.drawable.stat_sys_wifi_signal_3,
+            R.drawable.stat_sys_wifi_signal_4,
+        };
+    private static final int sWifiTemporarilyNotConnectedImage =
+            R.drawable.stat_sys_wifi_signal_0;
+
+    private int mLastWifiSignalLevel = -1;
+    private boolean mIsWifiConnected = false;
+
+    // sync state
+    // If sync is active the SyncActive icon is displayed. If sync is not active but
+    // sync is failing the SyncFailing icon is displayed. Otherwise neither are displayed.
+
+    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
+                updateBattery(intent);
+            }
+            else if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
+                updateAlarm(intent);
+            }
+            else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
+                updateSyncState(intent);
+            }
+            else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
+                onBatteryLow(intent);
+            }
+            else if (action.equals(Intent.ACTION_BATTERY_OKAY)
+                    || action.equals(Intent.ACTION_POWER_CONNECTED)) {
+                onBatteryOkay(intent);
+            }
+            else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED) ||
+                    action.equals(BluetoothHeadset.ACTION_STATE_CHANGED) ||
+                    action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED) ||
+                    action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
+                updateBluetooth(intent);
+            }
+            else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) ||
+                    action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) ||
+                    action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
+                updateWifi(intent);
+            }
+            else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) ||
+                    action.equals(LocationManager.GPS_FIX_CHANGE_ACTION)) {
+                updateGps(intent);
+            }
+            else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) ||
+                    action.equals(AudioManager.VIBRATE_SETTING_CHANGED_ACTION)) {
+                updateVolume();
+            }
+            else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
+                updateSimState(intent);
+            }
+            else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
+                updateTTY(intent);
+            }
+        }
+    };
+
+    public StatusBarPolicy(Context context) {
+        mContext = context;
+        mService = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);
+        mSignalStrength = new SignalStrength();
+        mBatteryStats = BatteryStatsService.getService();
+
+        // storage
+        mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
+        mStorageManager.registerListener(
+                new com.android.server.status.StorageNotification(context));
+
+        // battery
+        mService.setIcon("battery", com.android.internal.R.drawable.stat_sys_battery_unknown, 0);
+
+        // phone_signal
+        mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
+        mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
+        mService.setIcon("phone_signal", mPhoneSignalIconId, 0);
+
+        // register for phone state notifications.
+        ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
+                .listen(mPhoneStateListener,
+                          PhoneStateListener.LISTEN_SERVICE_STATE
+                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
+                        | PhoneStateListener.LISTEN_CALL_STATE
+                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
+                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
+
+        // data_connection
+        mService.setIcon("data_connection", R.drawable.stat_sys_data_connected_g, 0);
+        mService.setIconVisibility("data_connection", false);
+
+        // wifi
+        mService.setIcon("wifi", sWifiSignalImages[0], 0);
+        mService.setIconVisibility("wifi", false);
+        // wifi will get updated by the sticky intents
+
+        // TTY status
+        mService.setIcon("tty",  R.drawable.stat_sys_tty_mode, 0);
+        mService.setIconVisibility("tty", false);
+
+        // Cdma Roaming Indicator, ERI
+        mService.setIcon("cdma_eri", R.drawable.stat_sys_roaming_cdma_0, 0);
+        mService.setIconVisibility("cdma_eri", false);
+
+        // bluetooth status
+        mService.setIcon("bluetooth", R.drawable.stat_sys_data_bluetooth, 0);
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null) {
+            mBluetoothEnabled = adapter.isEnabled();
+        } else {
+            mBluetoothEnabled = false;
+        }
+        mBluetoothA2dpConnected = false;
+        mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED;
+        mBluetoothPbapState = BluetoothPbap.STATE_DISCONNECTED;
+        mService.setIconVisibility("bluetooth", mBluetoothEnabled);
+
+        // Gps status
+        mService.setIcon("gps", R.drawable.stat_sys_gps_acquiring_anim, 0);
+        mService.setIconVisibility("gps", false);
+
+        // Alarm clock
+        mService.setIcon("alarm_clock", R.drawable.stat_notify_alarm, 0);
+        mService.setIconVisibility("alarm_clock", false);
+
+        // Sync state
+        mService.setIcon("sync_active", com.android.internal.R.drawable.stat_notify_sync_anim0, 0);
+        mService.setIcon("sync_failing", com.android.internal.R.drawable.stat_notify_sync_error, 0);
+        mService.setIconVisibility("sync_active", false);
+        mService.setIconVisibility("sync_failing", false);
+
+        // volume
+        mService.setIcon("volume", R.drawable.stat_sys_ringer_silent, 0);
+        mService.setIconVisibility("volume", false);
+        updateVolume();
+
+        IntentFilter filter = new IntentFilter();
+
+        // Register for Intent broadcasts for...
+        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+        filter.addAction(Intent.ACTION_BATTERY_LOW);
+        filter.addAction(Intent.ACTION_BATTERY_OKAY);
+        filter.addAction(Intent.ACTION_POWER_CONNECTED);
+        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(BluetoothHeadset.ACTION_STATE_CHANGED);
+        filter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
+        filter.addAction(BluetoothPbap.PBAP_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
+        filter.addAction(LocationManager.GPS_ENABLED_CHANGE_ACTION);
+        filter.addAction(LocationManager.GPS_FIX_CHANGE_ACTION);
+        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
+        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
+
+        // load config to determine if to distinguish Hspa data icon
+        try {
+            mHspaDataDistinguishable = mContext.getResources().getBoolean(
+                    R.bool.config_hspa_data_distinguishable);
+        } catch (Exception e) {
+            mHspaDataDistinguishable = false;
+        }
+    }
+
+    private final void updateAlarm(Intent intent) {
+        boolean alarmSet = intent.getBooleanExtra("alarmSet", false);
+        mService.setIconVisibility("alarm_clock", alarmSet);
+    }
+
+    private final void updateSyncState(Intent intent) {
+        boolean isActive = intent.getBooleanExtra("active", false);
+        boolean isFailing = intent.getBooleanExtra("failing", false);
+        mService.setIconVisibility("sync_active", isActive);
+        // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never"
+        //mService.setIconVisibility("sync_failing", isFailing && !isActive);
+    }
+
+    private final void updateBattery(Intent intent) {
+        final int id = intent.getIntExtra("icon-small", 0);
+        int level = intent.getIntExtra("level", 0);
+        mService.setIcon("battery", id, level);
+
+        boolean plugged = intent.getIntExtra("plugged", 0) != 0;
+        level = intent.getIntExtra("level", -1);
+        if (false) {
+            Slog.d(TAG, "updateBattery level=" + level
+                    + " plugged=" + plugged
+                    + " mBatteryPlugged=" + mBatteryPlugged
+                    + " mBatteryLevel=" + mBatteryLevel
+                    + " mBatteryFirst=" + mBatteryFirst);
+        }
+
+        boolean oldPlugged = mBatteryPlugged;
+
+        mBatteryPlugged = plugged;
+        mBatteryLevel = level;
+
+        if (mBatteryFirst) {
+            mBatteryFirst = false;
+        }
+        /*
+         * No longer showing the battery view because it draws attention away
+         * from the USB storage notification. We could still show it when
+         * connected to a brick, but that could lead to the user into thinking
+         * the device does not charge when plugged into USB (since he/she would
+         * not see the same battery screen on USB as he sees on brick).
+         */
+        if (false) {
+            Slog.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
+        }
+    }
+
+    private void onBatteryLow(Intent intent) {
+        if (SHOW_LOW_BATTERY_WARNING) {
+            if (false) {
+                Slog.d(TAG, "mPhoneState=" + mPhoneState
+                      + " mLowBatteryDialog=" + mLowBatteryDialog
+                      + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
+            }
+
+            if (SHOW_BATTERY_WARNINGS_IN_CALL || mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
+                showLowBatteryWarning();
+            } else {
+                mBatteryShowLowOnEndCall = true;
+            }
+        }
+    }
+
+    private void onBatteryOkay(Intent intent) {
+        if (mLowBatteryDialog != null
+                && SHOW_LOW_BATTERY_WARNING) {
+            mLowBatteryDialog.dismiss();
+            mBatteryShowLowOnEndCall = false;
+        }
+    }
+
+    private void setBatteryLevel(View parent, int id, int height, int background, int level) {
+        ImageView v = (ImageView)parent.findViewById(id);
+        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)v.getLayoutParams();
+        lp.weight = height;
+        if (background != 0) {
+            v.setBackgroundResource(background);
+            Drawable bkg = v.getBackground();
+            bkg.setLevel(level);
+        }
+    }
+
+    private void showLowBatteryWarning() {
+        closeLastBatteryView();
+
+        // Show exact battery level.
+        CharSequence levelText = mContext.getString(
+                    R.string.battery_low_percent_format, mBatteryLevel);
+
+        if (mBatteryLevelTextView != null) {
+            mBatteryLevelTextView.setText(levelText);
+        } else {
+            View v = View.inflate(mContext, R.layout.battery_low, null);
+            mBatteryLevelTextView=(TextView)v.findViewById(R.id.level_percent);
+
+            mBatteryLevelTextView.setText(levelText);
+
+            AlertDialog.Builder b = new AlertDialog.Builder(mContext);
+                b.setCancelable(true);
+                b.setTitle(R.string.battery_low_title);
+                b.setView(v);
+                b.setIcon(android.R.drawable.ic_dialog_alert);
+                b.setPositiveButton(android.R.string.ok, null);
+
+                final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+                        | Intent.FLAG_ACTIVITY_NO_HISTORY);
+                if (intent.resolveActivity(mContext.getPackageManager()) != null) {
+                    b.setNegativeButton(R.string.battery_low_why,
+                            new DialogInterface.OnClickListener() {
+                        public void onClick(DialogInterface dialog, int which) {
+                            mContext.startActivity(intent);
+                            if (mLowBatteryDialog != null) {
+                                mLowBatteryDialog.dismiss();
+                            }
+                        }
+                    });
+                }
+
+            AlertDialog d = b.create();
+            d.setOnDismissListener(mLowBatteryListener);
+            d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+            d.show();
+            mLowBatteryDialog = d;
+        }
+
+        final ContentResolver cr = mContext.getContentResolver();
+        if (Settings.System.getInt(cr,
+                Settings.System.POWER_SOUNDS_ENABLED, 1) == 1)
+        {
+            final String soundPath = Settings.System.getString(cr,
+                Settings.System.LOW_BATTERY_SOUND);
+            if (soundPath != null) {
+                final Uri soundUri = Uri.parse("file://" + soundPath);
+                if (soundUri != null) {
+                    final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
+                    if (sfx != null) {
+                        sfx.setStreamType(AudioManager.STREAM_SYSTEM);
+                        sfx.play();
+                    }
+                }
+            }
+        }
+    }
+
+    private final void updateCallState(int state) {
+        mPhoneState = state;
+        if (false) {
+            Slog.d(TAG, "mPhoneState=" + mPhoneState
+                    + " mLowBatteryDialog=" + mLowBatteryDialog
+                    + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
+        }
+        if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
+            if (mBatteryShowLowOnEndCall) {
+                if (!mBatteryPlugged) {
+                    showLowBatteryWarning();
+                }
+                mBatteryShowLowOnEndCall = false;
+            }
+        } else {
+            if (mLowBatteryDialog != null) {
+                mLowBatteryDialog.dismiss();
+                mBatteryShowLowOnEndCall = true;
+            }
+        }
+    }
+
+    private DialogInterface.OnDismissListener mLowBatteryListener
+            = new DialogInterface.OnDismissListener() {
+        public void onDismiss(DialogInterface dialog) {
+            mLowBatteryDialog = null;
+            mBatteryLevelTextView = null;
+        }
+    };
+
+    private void scheduleCloseBatteryView() {
+        Message m = mHandler.obtainMessage(EVENT_BATTERY_CLOSE);
+        m.arg1 = (++mBatteryViewSequence);
+        mHandler.sendMessageDelayed(m, 3000);
+    }
+
+    private void closeLastBatteryView() {
+        if (mBatteryView != null) {
+            //mBatteryView.debug();
+            WindowManagerImpl.getDefault().removeView(mBatteryView);
+            mBatteryView = null;
+        }
+    }
+
+    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+            mSignalStrength = signalStrength;
+            updateSignalStrength();
+        }
+
+        @Override
+        public void onServiceStateChanged(ServiceState state) {
+            mServiceState = state;
+            updateSignalStrength();
+            updateCdmaRoamingIcon(state);
+            updateDataIcon();
+        }
+
+        @Override
+        public void onCallStateChanged(int state, String incomingNumber) {
+            updateCallState(state);
+            // In cdma, if a voice call is made, RSSI should switch to 1x.
+            if (isCdma()) {
+                updateSignalStrength();
+            }
+        }
+
+        @Override
+        public void onDataConnectionStateChanged(int state, int networkType) {
+            mDataState = state;
+            updateDataNetType(networkType);
+            updateDataIcon();
+        }
+
+        @Override
+        public void onDataActivity(int direction) {
+            mDataActivity = direction;
+            updateDataIcon();
+        }
+    };
+
+    private final void updateSimState(Intent intent) {
+        String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
+        if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
+            mSimState = IccCard.State.ABSENT;
+        }
+        else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
+            mSimState = IccCard.State.READY;
+        }
+        else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
+            final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
+            if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
+                mSimState = IccCard.State.PIN_REQUIRED;
+            }
+            else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
+                mSimState = IccCard.State.PUK_REQUIRED;
+            }
+            else {
+                mSimState = IccCard.State.NETWORK_LOCKED;
+            }
+        } else {
+            mSimState = IccCard.State.UNKNOWN;
+        }
+        updateDataIcon();
+    }
+
+    private boolean isCdma() {
+        return (mSignalStrength != null) && !mSignalStrength.isGsm();
+    }
+
+    private boolean isEvdo() {
+        return ( (mServiceState != null)
+                 && ((mServiceState.getRadioTechnology()
+                        == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
+                     || (mServiceState.getRadioTechnology()
+                        == ServiceState.RADIO_TECHNOLOGY_EVDO_A)
+                     || (mServiceState.getRadioTechnology()
+                        == ServiceState.RADIO_TECHNOLOGY_EVDO_B)));
+    }
+
+    private boolean hasService() {
+        if (mServiceState != null) {
+            switch (mServiceState.getState()) {
+                case ServiceState.STATE_OUT_OF_SERVICE:
+                case ServiceState.STATE_POWER_OFF:
+                    return false;
+                default:
+                    return true;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    private final void updateSignalStrength() {
+        int iconLevel = -1;
+        int[] iconList;
+
+        // Display signal strength while in "emergency calls only" mode
+        if (!hasService() && !mServiceState.isEmergencyOnly()) {
+            //Slog.d(TAG, "updateSignalStrength: no service");
+            if (Settings.System.getInt(mContext.getContentResolver(),
+                    Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
+                mPhoneSignalIconId = R.drawable.stat_sys_signal_flightmode;
+            } else {
+                mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
+            }
+            mService.setIcon("phone_signal", mPhoneSignalIconId, 0);
+            return;
+        }
+
+        if (!isCdma()) {
+            int asu = mSignalStrength.getGsmSignalStrength();
+
+            // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
+            // asu = 0 (-113dB or less) is very weak
+            // signal, its better to show 0 bars to the user in such cases.
+            // asu = 99 is a special case, where the signal strength is unknown.
+            if (asu <= 2 || asu == 99) iconLevel = 0;
+            else if (asu >= 12) iconLevel = 4;
+            else if (asu >= 8)  iconLevel = 3;
+            else if (asu >= 5)  iconLevel = 2;
+            else iconLevel = 1;
+
+            // Though mPhone is a Manager, this call is not an IPC
+            if (mPhone.isNetworkRoaming()) {
+                iconList = sSignalImages_r;
+            } else {
+                iconList = sSignalImages;
+            }
+        } else {
+            iconList = this.sSignalImages;
+
+            // If 3G(EV) and 1x network are available than 3G should be
+            // displayed, displayed RSSI should be from the EV side.
+            // If a voice call is made then RSSI should switch to 1x.
+            if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
+                iconLevel = getEvdoLevel();
+                if (false) {
+                    Slog.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel());
+                }
+            } else {
+                iconLevel = getCdmaLevel();
+            }
+        }
+        mPhoneSignalIconId = iconList[iconLevel];
+        mService.setIcon("phone_signal", mPhoneSignalIconId, 0);
+    }
+
+    private int getCdmaLevel() {
+        final int cdmaDbm = mSignalStrength.getCdmaDbm();
+        final int cdmaEcio = mSignalStrength.getCdmaEcio();
+        int levelDbm = 0;
+        int levelEcio = 0;
+
+        if (cdmaDbm >= -75) levelDbm = 4;
+        else if (cdmaDbm >= -85) levelDbm = 3;
+        else if (cdmaDbm >= -95) levelDbm = 2;
+        else if (cdmaDbm >= -100) levelDbm = 1;
+        else levelDbm = 0;
+
+        // Ec/Io are in dB*10
+        if (cdmaEcio >= -90) levelEcio = 4;
+        else if (cdmaEcio >= -110) levelEcio = 3;
+        else if (cdmaEcio >= -130) levelEcio = 2;
+        else if (cdmaEcio >= -150) levelEcio = 1;
+        else levelEcio = 0;
+
+        return (levelDbm < levelEcio) ? levelDbm : levelEcio;
+    }
+
+    private int getEvdoLevel() {
+        int evdoDbm = mSignalStrength.getEvdoDbm();
+        int evdoSnr = mSignalStrength.getEvdoSnr();
+        int levelEvdoDbm = 0;
+        int levelEvdoSnr = 0;
+
+        if (evdoDbm >= -65) levelEvdoDbm = 4;
+        else if (evdoDbm >= -75) levelEvdoDbm = 3;
+        else if (evdoDbm >= -90) levelEvdoDbm = 2;
+        else if (evdoDbm >= -105) levelEvdoDbm = 1;
+        else levelEvdoDbm = 0;
+
+        if (evdoSnr >= 7) levelEvdoSnr = 4;
+        else if (evdoSnr >= 5) levelEvdoSnr = 3;
+        else if (evdoSnr >= 3) levelEvdoSnr = 2;
+        else if (evdoSnr >= 1) levelEvdoSnr = 1;
+        else levelEvdoSnr = 0;
+
+        return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
+    }
+
+    private final void updateDataNetType(int net) {
+        switch (net) {
+        case TelephonyManager.NETWORK_TYPE_EDGE:
+            mDataIconList = sDataNetType_e;
+            break;
+        case TelephonyManager.NETWORK_TYPE_UMTS:
+            mDataIconList = sDataNetType_3g;
+            break;
+        case TelephonyManager.NETWORK_TYPE_HSDPA:
+        case TelephonyManager.NETWORK_TYPE_HSUPA:
+        case TelephonyManager.NETWORK_TYPE_HSPA:
+            if (mHspaDataDistinguishable) {
+                mDataIconList = sDataNetType_h;
+            } else {
+                mDataIconList = sDataNetType_3g;
+            }
+            break;
+        case TelephonyManager.NETWORK_TYPE_CDMA:
+            // display 1xRTT for IS95A/B
+            mDataIconList = this.sDataNetType_1x;
+            break;
+        case TelephonyManager.NETWORK_TYPE_1xRTT:
+            mDataIconList = this.sDataNetType_1x;
+            break;
+        case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
+        case TelephonyManager.NETWORK_TYPE_EVDO_A:
+        case TelephonyManager.NETWORK_TYPE_EVDO_B:
+            mDataIconList = sDataNetType_3g;
+            break;
+        default:
+            mDataIconList = sDataNetType_g;
+        break;
+        }
+    }
+
+    private final void updateDataIcon() {
+        int iconId;
+        boolean visible = true;
+
+        if (!isCdma()) {
+            // GSM case, we have to check also the sim state
+            if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
+                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
+                    switch (mDataActivity) {
+                        case TelephonyManager.DATA_ACTIVITY_IN:
+                            iconId = mDataIconList[1];
+                            break;
+                        case TelephonyManager.DATA_ACTIVITY_OUT:
+                            iconId = mDataIconList[2];
+                            break;
+                        case TelephonyManager.DATA_ACTIVITY_INOUT:
+                            iconId = mDataIconList[3];
+                            break;
+                        default:
+                            iconId = mDataIconList[0];
+                            break;
+                    }
+                    mService.setIcon("data_connection", iconId, 0);
+                } else {
+                    visible = false;
+                }
+            } else {
+                iconId = R.drawable.stat_sys_no_sim;
+                mService.setIcon("data_connection", iconId, 0);
+            }
+        } else {
+            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
+            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
+                switch (mDataActivity) {
+                    case TelephonyManager.DATA_ACTIVITY_IN:
+                        iconId = mDataIconList[1];
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_OUT:
+                        iconId = mDataIconList[2];
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_INOUT:
+                        iconId = mDataIconList[3];
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_DORMANT:
+                    default:
+                        iconId = mDataIconList[0];
+                        break;
+                }
+                mService.setIcon("data_connection", iconId, 0);
+            } else {
+                visible = false;
+            }
+        }
+
+        long ident = Binder.clearCallingIdentity();
+        try {
+            mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
+        } catch (RemoteException e) {
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+
+        if (mDataIconVisible != visible) {
+            mService.setIconVisibility("data_connection", visible);
+            mDataIconVisible = visible;
+        }
+    }
+
+    private final void updateVolume() {
+        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        final int ringerMode = audioManager.getRingerMode();
+        final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
+                ringerMode == AudioManager.RINGER_MODE_VIBRATE;
+        final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)
+                ? R.drawable.stat_sys_ringer_vibrate
+                : R.drawable.stat_sys_ringer_silent;
+
+        if (visible) {
+            mService.setIcon("volume", iconId, 0);
+        }
+        if (visible != mVolumeVisible) {
+            mService.setIconVisibility("volume", visible);
+            mVolumeVisible = visible;
+        }
+    }
+
+    private final void updateBluetooth(Intent intent) {
+        int iconId = R.drawable.stat_sys_data_bluetooth;
+        String action = intent.getAction();
+        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
+            mBluetoothEnabled = state == BluetoothAdapter.STATE_ON;
+        } else if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) {
+            mBluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
+                    BluetoothHeadset.STATE_ERROR);
+        } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
+            BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
+            if (a2dp.getConnectedSinks().size() != 0) {
+                mBluetoothA2dpConnected = true;
+            } else {
+                mBluetoothA2dpConnected = false;
+            }
+        } else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
+            mBluetoothPbapState = intent.getIntExtra(BluetoothPbap.PBAP_STATE,
+                    BluetoothPbap.STATE_DISCONNECTED);
+        } else {
+            return;
+        }
+
+        if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED || mBluetoothA2dpConnected ||
+                mBluetoothPbapState == BluetoothPbap.STATE_CONNECTED) {
+            iconId = R.drawable.stat_sys_data_bluetooth_connected;
+        }
+
+        mService.setIcon("bluetooth", iconId, 0);
+        mService.setIconVisibility("bluetooth", mBluetoothEnabled);
+    }
+
+    private final void updateWifi(Intent intent) {
+        final String action = intent.getAction();
+        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+
+            final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
+
+            if (!enabled) {
+                // If disabled, hide the icon. (We show icon when connected.)
+                mService.setIconVisibility("wifi", false);
+            }
+
+        } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
+            final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED,
+                                                           false);
+            if (!enabled) {
+                mService.setIconVisibility("wifi", false);
+            }
+        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+
+            final NetworkInfo networkInfo = (NetworkInfo)
+                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
+
+            int iconId;
+            if (networkInfo != null && networkInfo.isConnected()) {
+                mIsWifiConnected = true;
+                if (mLastWifiSignalLevel == -1) {
+                    iconId = sWifiSignalImages[0];
+                } else {
+                    iconId = sWifiSignalImages[mLastWifiSignalLevel];
+                }
+
+                // Show the icon since wi-fi is connected
+                mService.setIconVisibility("wifi", true);
+
+            } else {
+                mLastWifiSignalLevel = -1;
+                mIsWifiConnected = false;
+                iconId = sWifiSignalImages[0];
+
+                // Hide the icon since we're not connected
+                mService.setIconVisibility("wifi", false);
+            }
+
+            mService.setIcon("wifi", iconId, 0);
+        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
+            int iconId;
+            final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
+            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
+                                                                  sWifiSignalImages.length);
+            if (newSignalLevel != mLastWifiSignalLevel) {
+                mLastWifiSignalLevel = newSignalLevel;
+                if (mIsWifiConnected) {
+                    iconId = sWifiSignalImages[newSignalLevel];
+                } else {
+                    iconId = sWifiTemporarilyNotConnectedImage;
+                }
+                mService.setIcon("wifi", iconId, 0);
+            }
+        }
+    }
+
+    private final void updateGps(Intent intent) {
+        final String action = intent.getAction();
+        final boolean enabled = intent.getBooleanExtra(LocationManager.EXTRA_GPS_ENABLED, false);
+
+        if (action.equals(LocationManager.GPS_FIX_CHANGE_ACTION) && enabled) {
+            // GPS is getting fixes
+            mService.setIcon("gps", com.android.internal.R.drawable.stat_sys_gps_on, 0);
+            mService.setIconVisibility("gps", true);
+        } else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
+            // GPS is off
+            mService.setIconVisibility("gps", false);
+        } else {
+            // GPS is on, but not receiving fixes
+            mService.setIcon("gps", R.drawable.stat_sys_gps_acquiring_anim, 0);
+            mService.setIconVisibility("gps", true);
+        }
+    }
+
+    private final void updateTTY(Intent intent) {
+        final String action = intent.getAction();
+        final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
+
+        if (false) Slog.v(TAG, "updateTTY: enabled: " + enabled);
+
+        if (enabled) {
+            // TTY is on
+            if (false) Slog.v(TAG, "updateTTY: set TTY on");
+            mService.setIcon("tty", R.drawable.stat_sys_tty_mode, 0);
+            mService.setIconVisibility("tty", true);
+        } else {
+            // TTY is off
+            if (false) Slog.v(TAG, "updateTTY: set TTY off");
+            mService.setIconVisibility("tty", false);
+        }
+    }
+
+    private final void updateCdmaRoamingIcon(ServiceState state) {
+        if (!hasService()) {
+            mService.setIconVisibility("cdma_eri", false);
+            return;
+        }
+
+        if (!isCdma()) {
+            mService.setIconVisibility("cdma_eri", false);
+            return;
+        }
+
+        int[] iconList = sRoamingIndicatorImages_cdma;
+        int iconIndex = state.getCdmaEriIconIndex();
+        int iconMode = state.getCdmaEriIconMode();
+
+        if (iconIndex == -1) {
+            Slog.e(TAG, "getCdmaEriIconIndex returned null, skipping ERI icon update");
+            return;
+        }
+
+        if (iconMode == -1) {
+            Slog.e(TAG, "getCdmeEriIconMode returned null, skipping ERI icon update");
+            return;
+        }
+
+        if (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) {
+            if (false) Slog.v(TAG, "Cdma ROAMING_INDICATOR_OFF, removing ERI icon");
+            mService.setIconVisibility("cdma_eri", false);
+            return;
+        }
+
+        switch (iconMode) {
+            case EriInfo.ROAMING_ICON_MODE_NORMAL:
+                mService.setIcon("cdma_eri", iconList[iconIndex], 0);
+                mService.setIconVisibility("cdma_eri", true);
+                break;
+            case EriInfo.ROAMING_ICON_MODE_FLASH:
+                mService.setIcon("cdma_eri", R.drawable.stat_sys_roaming_cdma_flash, 0);
+                mService.setIconVisibility("cdma_eri", true);
+                break;
+
+        }
+        mService.setIcon("phone_signal", mPhoneSignalIconId, 0);
+    }
+
+
+    private class StatusBarHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case EVENT_BATTERY_CLOSE:
+                if (msg.arg1 == mBatteryViewSequence) {
+                    closeLastBatteryView();
+                }
+                break;
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
new file mode 100644
index 0000000..4d9e695
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.Slog;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+
+import com.android.internal.statusbar.IStatusBar;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.StatusBarNotification;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+
+public abstract class StatusBarService extends Service implements CommandQueue.Callbacks {
+    private static final String TAG = "StatusBarService";
+
+    CommandQueue mCommandQueue;
+    IStatusBarService mBarService;
+
+    /* TODO
+    H mHandler = new H();
+    Object mQueueLock = new Object();
+    NotificationCallbacks mNotificationCallbacks;
+    */
+
+    @Override
+    public void onCreate() {
+        // Connect in to the status bar manager service
+        StatusBarIconList iconList = new StatusBarIconList();
+        ArrayList<IBinder> notificationKeys = new ArrayList<IBinder>();
+        ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();
+        mCommandQueue = new CommandQueue(this, iconList);
+        mBarService = IStatusBarService.Stub.asInterface(
+                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        try {
+            mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications);
+        } catch (RemoteException ex) {
+            // If the system process isn't there we're doomed anyway.
+        }
+
+        // Set up the initial icon state
+        int N = iconList.size();
+        int viewIndex = 0;
+        for (int i=0; i<N; i++) {
+            StatusBarIcon icon = iconList.getIcon(i);
+            if (icon != null) {
+                addIcon(iconList.getSlot(i), i, viewIndex, icon);
+                viewIndex++;
+            }
+        }
+
+        // Set up the initial notification state
+        N = notificationKeys.size();
+        if (N == notifications.size()) {
+            for (int i=0; i<N; i++) {
+                addNotification(notificationKeys.get(i), notifications.get(i));
+            }
+        } else {
+            Log.wtf(TAG, "Notification list length mismatch: keys=" + N
+                    + " notifications=" + notifications.size());
+        }
+
+        // Put up the view
+        addStatusBarView();
+    }
+
+    @Override
+    public void onDestroy() {
+        // we're never destroyed
+    }
+
+    /**
+     * Nobody binds to us.
+     */
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    /**
+     * Implement this to add the main status bar view.
+     */
+    protected abstract void addStatusBarView();
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStarter.java
new file mode 100644
index 0000000..2b9dfb0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStarter.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.BroadcastReceiver;
+import android.util.Log;
+
+/**
+ * Receive a broadcast from the StatusBarManagerService at boot time, and
+ * kick off the StatusBarService.
+ */
+public class StatusBarStarter extends BroadcastReceiver {
+    private static final String TAG = "StatusBarStarter";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Log.d(TAG, "StatusBarStarter onReceive intent=" + intent);
+        context.startService(new Intent(context, PhoneStatusBarService.class));
+    }
+}
+
+
diff --git a/services/java/com/android/server/status/StatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
similarity index 96%
rename from services/java/com/android/server/status/StatusBarView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
index 5e1f572..466cc75 100644
--- a/services/java/com/android/server/status/StatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.content.res.Configuration;
@@ -27,14 +27,14 @@
 import android.view.ViewParent;
 import android.widget.FrameLayout;
 
-import com.android.internal.R;
+import com.android.systemui.R;
 
 public class StatusBarView extends FrameLayout {
     private static final String TAG = "StatusBarView";
 
     static final int DIM_ANIM_TIME = 400;
     
-    StatusBarService mService;
+    PhoneStatusBarService mService;
     boolean mTracking;
     int mStartX, mStartY;
     ViewGroup mNotificationIcons;
@@ -94,7 +94,7 @@
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-        mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE);
+        mService.updateExpandedViewPos(PhoneStatusBarService.EXPANDED_LEAVE_ALONE);
     }
 
     @Override
diff --git a/services/java/com/android/server/status/Ticker.java b/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
similarity index 79%
rename from services/java/com/android/server/status/Ticker.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
index e47185b..07e8653 100644
--- a/services/java/com/android/server/status/Ticker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/Ticker.java
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
-
-import com.android.internal.R;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
@@ -35,12 +33,24 @@
 
 import java.util.ArrayList;
 
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarNotification;
+import com.android.internal.util.CharSequences;
+import com.android.systemui.R;
 
-abstract class Ticker {
+public abstract class Ticker {
     private static final int TICKER_SEGMENT_DELAY = 3000;
     
+    private Context mContext;
+    private Handler mHandler = new Handler();
+    private ArrayList<Segment> mSegments = new ArrayList();
+    private TextPaint mPaint;
+    private View mTickerView;
+    private ImageSwitcher mIconSwitcher;
+    private TextSwitcher mTextSwitcher;
+
     private final class Segment {
-        NotificationData notificationData;
+        StatusBarNotification notification;
         Drawable icon;
         CharSequence text;
         int current;
@@ -116,8 +126,8 @@
             return null;
         }
 
-        Segment(NotificationData n, Drawable icon, CharSequence text) {
-            this.notificationData = n;
+        Segment(StatusBarNotification n, Drawable icon, CharSequence text) {
+            this.notification = n;
             this.icon = icon;
             this.text = text;
             int index = 0;
@@ -131,14 +141,8 @@
         }
     };
 
-    private Handler mHandler = new Handler();
-    private ArrayList<Segment> mSegments = new ArrayList();
-    private TextPaint mPaint;
-    private View mTickerView;
-    private ImageSwitcher mIconSwitcher;
-    private TextSwitcher mTextSwitcher;
-
     Ticker(Context context, StatusBarView sb) {
+        mContext = context;
         mTickerView = sb.findViewById(R.id.ticker);
 
         mIconSwitcher = (ImageSwitcher)sb.findViewById(R.id.tickerIcon);
@@ -158,20 +162,34 @@
         mPaint = text.getPaint();
     }
 
-    void addEntry(NotificationData n, Drawable icon, CharSequence text) {
+
+    void addEntry(StatusBarNotification n) {
         int initialCount = mSegments.size();
 
-        Segment newSegment = new Segment(n, icon, text);
+        // If what's being displayed has the same text and icon, just drop it
+        // (which will let the current one finish, this happens when apps do
+        // a notification storm).
+        if (initialCount > 0) {
+            final Segment seg = mSegments.get(0);
+            if (n.pkg.equals(seg.notification.pkg)
+                    && n.notification.icon == seg.notification.notification.icon
+                    && n.notification.iconLevel == seg.notification.notification.iconLevel
+                    && CharSequences.equals(seg.notification.notification.tickerText,
+                        n.notification.tickerText)) {
+                return;
+            }
+        }
 
-        // prune out any preexisting ones for this notification, but not the current one.
-        // let that finish, even if it's the same id
-        for (int i=1; i<initialCount; i++) {
+        final Drawable icon = StatusBarIconView.getIcon(mContext,
+                new StatusBarIcon(n.pkg, n.notification.icon, n.notification.iconLevel, 0));
+        final Segment newSegment = new Segment(n, icon, n.notification.tickerText);
+
+        // If there's already a notification schedule for this package and id, remove it.
+        for (int i=0; i<initialCount; i++) {
             Segment seg = mSegments.get(i);
-            if (n.id == seg.notificationData.id && n.pkg.equals(seg.notificationData.pkg)) {
+            if (n.id == seg.notification.id && n.pkg.equals(seg.notification.pkg)) {
                 // just update that one to use this new data instead
-                mSegments.set(i, newSegment);
-                // and since we know initialCount != 0, just return
-                return ;
+                mSegments.remove(i);
             }
         }
 
@@ -194,6 +212,15 @@
         }
     }
 
+    void removeEntry(StatusBarNotification n) {
+        for (int i=mSegments.size()-1; i>=0; i--) {
+            Segment seg = mSegments.get(i);
+            if (n.id == seg.notification.id && n.pkg.equals(seg.notification.pkg)) {
+                mSegments.remove(i);
+            }
+        }
+    }
+
     void halt() {
         mHandler.removeCallbacks(mAdvanceTicker);
         mSegments.clear();
diff --git a/services/java/com/android/server/status/TickerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TickerView.java
similarity index 95%
rename from services/java/com/android/server/status/TickerView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/TickerView.java
index 099dffb..9749ae4 100644
--- a/services/java/com/android/server/status/TickerView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TickerView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.util.AttributeSet;
diff --git a/services/java/com/android/server/status/TrackingPatternView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingPatternView.java
similarity index 97%
rename from services/java/com/android/server/status/TrackingPatternView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/TrackingPatternView.java
index 2c91aa4..ba6f15d 100644
--- a/services/java/com/android/server/status/TrackingPatternView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingPatternView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.content.res.TypedArray;
diff --git a/services/java/com/android/server/status/TrackingView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
similarity index 93%
rename from services/java/com/android/server/status/TrackingView.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
index 8ec39c0..c59eb6a 100644
--- a/services/java/com/android/server/status/TrackingView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.status;
+package com.android.systemui.statusbar;
 
 import android.content.Context;
 import android.util.AttributeSet;
@@ -26,7 +26,7 @@
 
 public class TrackingView extends LinearLayout {
     final Display mDisplay;
-    StatusBarService mService;
+    PhoneStatusBarService mService;
     boolean mTracking;
     int mStartX, mStartY;
 
@@ -48,7 +48,7 @@
         switch (event.getKeyCode()) {
         case KeyEvent.KEYCODE_BACK:
             if (down) {
-                mService.deactivate();
+                //mService.deactivate();
             }
             return true;
         }
diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java
index c255041..eb61f5e 100644
--- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -145,8 +145,8 @@
     private Context mContext;
     private AlarmManager mAlarmManager;
     private StatusBarManager mStatusBarManager;
-    private boolean mShowLockIcon = false;
-    private IBinder mSecureLockIcon = null;
+    private boolean mShowLockIcon;
+    private boolean mShowingLockIcon;
 
     private boolean mSystemReady;
 
@@ -1036,14 +1036,15 @@
             if (mShowLockIcon) {
                 // Give feedback to user when secure keyguard is active and engaged
                 if (mShowing && isSecure()) {
-                    if (mSecureLockIcon == null) {
-                        mSecureLockIcon = mStatusBarManager.addIcon("secure",
-                            com.android.internal.R.drawable.stat_sys_secure, 0);
+                    if (!mShowingLockIcon) {
+                        mStatusBarManager.setIcon("secure",
+                                com.android.internal.R.drawable.stat_sys_secure, 0);
+                        mShowingLockIcon = true;
                     }
                 } else {
-                    if (mSecureLockIcon != null) {
-                        mStatusBarManager.removeIcon(mSecureLockIcon);
-                        mSecureLockIcon = null;
+                    if (mShowingLockIcon) {
+                        mStatusBarManager.removeIcon("secure");
+                        mShowingLockIcon = false;
                     }
                 }
             }
diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java
index a7c278b..73a57ee 100755
--- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
-import android.app.IStatusBar;
 import android.app.IUiModeManager;
 import android.app.UiModeManager;
 import android.content.ActivityNotFoundException;
@@ -47,6 +46,7 @@
 import android.provider.Settings;
 
 import com.android.internal.policy.PolicyManager;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.widget.PointerLocationView;
 
@@ -1140,22 +1140,6 @@
                     return true;
                 }
             }
-        } else if (code == KeyEvent.KEYCODE_NOTIFICATION) {
-            if (down) {
-                // this key doesn't exist on current hardware, but if a device
-                // didn't have a touchscreen, it would want one of these to open
-                // the status bar.
-                IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar"));
-                if (sbs != null) {
-                    try {
-                        sbs.toggle();
-                    } catch (RemoteException e) {
-                        // we're screwed anyway, since it's in this process
-                        throw new RuntimeException(e);
-                    }
-                }
-            }
-            return true;
         } else if (code == KeyEvent.KEYCODE_SEARCH) {
             if (down) {
                 if (repeatCount == 0) {
@@ -1537,11 +1521,11 @@
         }
         
         if (changes != 0 && hiding) {
-            IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar"));
+            IStatusBarService sbs = IStatusBarService.Stub.asInterface(ServiceManager.getService("statusbar"));
             if (sbs != null) {
                 try {
                     // Make sure the window shade is hidden.
-                    sbs.deactivate();
+                    sbs.collapse();
                 } catch (RemoteException e) {
                 }
             }
diff --git a/preloaded-classes b/preloaded-classes
index f300fe7..b602039 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -31,7 +31,6 @@
 android.app.IActivityManager
 android.app.IActivityManager$ContentProviderHolder
 android.app.IAlarmManager$Stub
-android.app.IStatusBar$Stub
 android.app.ITransientNotification$Stub
 android.app.Instrumentation
 android.app.IntentService
@@ -654,6 +653,11 @@
 com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState
 com.android.internal.policy.impl.PhoneWindowManager
 com.android.internal.policy.impl.Policy
+com.android.internal.statusbar.IStatusBar
+com.android.internal.statusbar.IStatusBar$Stub
+com.android.internal.statusbar.IStatusBarService$Stub
+com.android.internal.statusbar.IStatusBarService$Stub
+com.android.internal.statusbar.StatusBarIcon
 com.android.internal.telephony.GsmAlphabet
 com.android.internal.telephony.ITelephony$Stub
 com.android.internal.telephony.ITelephony$Stub$Proxy
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java
index 62cf7076..4a0df59 100644
--- a/services/java/com/android/server/DeviceStorageMonitorService.java
+++ b/services/java/com/android/server/DeviceStorageMonitorService.java
@@ -280,7 +280,9 @@
         mTotalMemory = ((long)mDataFileStats.getBlockCount() *
                         mDataFileStats.getBlockSize())/100L;
         mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW);
+        mStorageLowIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
         mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK);
+        mStorageOkIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
         checkMemory(true);
     }
 
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 5bf66e4..a1f26f2 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -26,8 +26,7 @@
 import com.android.internal.view.IInputMethodSession;
 import com.android.internal.view.InputBindResult;
 
-import com.android.server.status.IconData;
-import com.android.server.status.StatusBarService;
+import com.android.server.status.StatusBarManagerService;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -110,9 +109,7 @@
     final Context mContext;
     final Handler mHandler;
     final SettingsObserver mSettingsObserver;
-    final StatusBarService mStatusBar;
-    final IBinder mInputMethodIcon;
-    final IconData mInputMethodData;
+    final StatusBarManagerService mStatusBar;
     final IWindowManager mIWindowManager;
     final HandlerCaller mCaller;
 
@@ -447,7 +444,7 @@
         }
     }
 
-    public InputMethodManagerService(Context context, StatusBarService statusBar) {
+    public InputMethodManagerService(Context context, StatusBarManagerService statusBar) {
         mContext = context;
         mHandler = new Handler(this);
         mIWindowManager = IWindowManager.Stub.asInterface(
@@ -508,9 +505,7 @@
         }
 
         mStatusBar = statusBar;
-        mInputMethodData = IconData.makeIcon("ime", null, 0, 0, 0);
-        mInputMethodIcon = statusBar.addIcon(mInputMethodData, null);
-        statusBar.setIconVisibility(mInputMethodIcon, false);
+        statusBar.setIconVisibility("ime", false);
 
         mSettingsObserver = new SettingsObserver(mHandler);
         updateFromSettingsLocked();
@@ -912,7 +907,7 @@
             mEnabledSession = null;
             mCurMethod = null;
         }
-        mStatusBar.setIconVisibility(mInputMethodIcon, false);
+        mStatusBar.setIconVisibility("ime", false);
     }
 
     public void onServiceDisconnected(ComponentName name) {
@@ -946,13 +941,11 @@
             synchronized (mMethodMap) {
                 if (iconId == 0) {
                     if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
-                    mStatusBar.setIconVisibility(mInputMethodIcon, false);
+                    mStatusBar.setIconVisibility("ime", false);
                 } else if (packageName != null) {
                     if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
-                    mInputMethodData.iconId = iconId;
-                    mInputMethodData.iconPackage = packageName;
-                    mStatusBar.updateIcon(mInputMethodIcon, mInputMethodData, null);
-                    mStatusBar.setIconVisibility(mInputMethodIcon, true);
+                    mStatusBar.setIcon("ime", packageName, iconId, 0);
+                    mStatusBar.setIconVisibility("ime", true);
                 }
             }
         } finally {
@@ -1734,8 +1727,6 @@
                 p.println("    sessionRequested=" + ci.sessionRequested);
                 p.println("    curSession=" + ci.curSession);
             }
-            p.println("  mInputMethodIcon=" + mInputMethodIcon);
-            p.println("  mInputMethodData=" + mInputMethodData);
             p.println("  mCurMethodId=" + mCurMethodId);
             client = mCurClient;
             p.println("  mCurClient=" + client + " mCurSeq=" + mCurSeq);
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 73d17ea..ac3b23b 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -16,9 +16,8 @@
 
 package com.android.server;
 
-import com.android.server.status.IconData;
-import com.android.server.status.NotificationData;
-import com.android.server.status.StatusBarService;
+import com.android.internal.statusbar.StatusBarNotification;
+import com.android.server.status.StatusBarManagerService;
 
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
@@ -86,7 +85,7 @@
     final IBinder mForegroundToken = new Binder();
 
     private WorkerHandler mHandler;
-    private StatusBarService mStatusBarService;
+    private StatusBarManagerService mStatusBar;
     private LightsService mLightsService;
     private LightsService.Light mBatteryLight;
     private LightsService.Light mNotificationLight;
@@ -238,8 +237,8 @@
         }
     }
 
-    private StatusBarService.NotificationCallbacks mNotificationCallbacks
-            = new StatusBarService.NotificationCallbacks() {
+    private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks
+            = new StatusBarManagerService.NotificationCallbacks() {
 
         public void onSetDisabled(int status) {
             synchronized (mNotificationList) {
@@ -405,7 +404,7 @@
         }
     }
 
-    NotificationManagerService(Context context, StatusBarService statusBar,
+    NotificationManagerService(Context context, StatusBarManagerService statusBar,
             LightsService lights)
     {
         super();
@@ -417,7 +416,7 @@
         mToastQueue = new ArrayList<ToastRecord>();
         mHandler = new WorkerHandler();
 
-        mStatusBarService = statusBar;
+        mStatusBar = statusBar;
         statusBar.setNotificationCallbacks(mNotificationCallbacks);
 
         mBatteryLight = lights.getLight(LightsService.LIGHT_ID_BATTERY);
@@ -705,36 +704,12 @@
             }
 
             if (notification.icon != 0) {
-                IconData icon = IconData.makeIcon(null, pkg, notification.icon,
-                                                    notification.iconLevel,
-                                                    notification.number);
-                CharSequence truncatedTicker = notification.tickerText;
-
-                // TODO: make this restriction do something smarter like never fill
-                // more than two screens.  "Why would anyone need more than 80 characters." :-/
-                final int maxTickerLen = 80;
-                if (truncatedTicker != null && truncatedTicker.length() > maxTickerLen) {
-                    truncatedTicker = truncatedTicker.subSequence(0, maxTickerLen);
-                }
-
-                NotificationData n = new NotificationData();
-                n.pkg = pkg;
-                n.tag = tag;
-                n.id = id;
-                n.when = notification.when;
-                n.tickerText = truncatedTicker;
-                n.ongoingEvent = (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0;
-                if (!n.ongoingEvent && (notification.flags & Notification.FLAG_NO_CLEAR) == 0) {
-                    n.clearable = true;
-                }
-                n.contentView = notification.contentView;
-                n.contentIntent = notification.contentIntent;
-                n.deleteIntent = notification.deleteIntent;
+                StatusBarNotification n = new StatusBarNotification(pkg, id, tag, notification);
                 if (old != null && old.statusBarKey != null) {
                     r.statusBarKey = old.statusBarKey;
                     long identity = Binder.clearCallingIdentity();
                     try {
-                        mStatusBarService.updateIcon(r.statusBarKey, icon, n);
+                        mStatusBar.updateNotification(r.statusBarKey, n);
                     }
                     finally {
                         Binder.restoreCallingIdentity(identity);
@@ -742,21 +717,19 @@
                 } else {
                     long identity = Binder.clearCallingIdentity();
                     try {
-                        r.statusBarKey = mStatusBarService.addIcon(icon, n);
+                        r.statusBarKey = mStatusBar.addNotification(n);
                         mAttentionLight.pulse();
                     }
                     finally {
                         Binder.restoreCallingIdentity(identity);
                     }
                 }
-
                 sendAccessibilityEvent(notification, pkg);
-
             } else {
                 if (old != null && old.statusBarKey != null) {
                     long identity = Binder.clearCallingIdentity();
                     try {
-                        mStatusBarService.removeIcon(old.statusBarKey);
+                        mStatusBar.removeNotification(old.statusBarKey);
                     }
                     finally {
                         Binder.restoreCallingIdentity(identity);
@@ -864,7 +837,7 @@
         if (r.notification.icon != 0) {
             long identity = Binder.clearCallingIdentity();
             try {
-                mStatusBarService.removeIcon(r.statusBarKey);
+                mStatusBar.removeNotification(r.statusBarKey);
             }
             finally {
                 Binder.restoreCallingIdentity(identity);
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 599023c..79da3cf 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -3648,21 +3648,19 @@
 
             installedNativeLibraries = true;
 
+            // Always extract the shared library
             String sharedLibraryFilePath = sharedLibraryDir.getPath() +
                 File.separator + libFileName;
             File sharedLibraryFile = new File(sharedLibraryFilePath);
-            if (! sharedLibraryFile.exists() ||
-                sharedLibraryFile.length() != entry.getSize() ||
-                sharedLibraryFile.lastModified() != entry.getTime()) {
-                if (Config.LOGD) {
-                    Log.d(TAG, "Caching shared lib " + entry.getName());
-                }
-                if (mInstaller == null) {
-                    sharedLibraryDir.mkdir();
-                }
-                cacheNativeBinaryLI(pkg, zipFile, entry, sharedLibraryDir,
-                        sharedLibraryFile);
+
+            if (Config.LOGD) {
+                Log.d(TAG, "Caching shared lib " + entry.getName());
             }
+            if (mInstaller == null) {
+                sharedLibraryDir.mkdir();
+            }
+            cacheNativeBinaryLI(pkg, zipFile, entry, sharedLibraryDir,
+                    sharedLibraryFile);
         }
         if (!hasNativeLibraries)
             return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES;
@@ -3704,18 +3702,16 @@
             String installGdbServerPath = installGdbServerDir.getPath() +
                 "/" + GDBSERVER;
             File installGdbServerFile = new File(installGdbServerPath);
-            if (! installGdbServerFile.exists() ||
-                installGdbServerFile.length() != entry.getSize() ||
-                installGdbServerFile.lastModified() != entry.getTime()) {
-                if (Config.LOGD) {
-                    Log.d(TAG, "Caching gdbserver " + entry.getName());
-                }
-                if (mInstaller == null) {
-                    installGdbServerDir.mkdir();
-                }
-                cacheNativeBinaryLI(pkg, zipFile, entry, installGdbServerDir,
-                        installGdbServerFile);
+
+            if (Config.LOGD) {
+                Log.d(TAG, "Caching gdbserver " + entry.getName());
             }
+            if (mInstaller == null) {
+                installGdbServerDir.mkdir();
+            }
+            cacheNativeBinaryLI(pkg, zipFile, entry, installGdbServerDir,
+                    installGdbServerFile);
+
             return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES;
         }
         return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES;
@@ -3729,6 +3725,16 @@
     // one if ro.product.cpu.abi2 is defined.
     //
     private int cachePackageSharedLibsLI(PackageParser.Package pkg, File scanFile) {
+        // Remove all native binaries from a directory. This is used when upgrading
+        // a package: in case the new .apk doesn't contain a native binary that was
+        // in the old one (and thus installed), we need to remove it from
+        // /data/data/<appname>/lib
+        //
+        // The simplest way to do that is to remove all files in this directory,
+        // since it is owned by "system", applications are not supposed to write
+        // anything there.
+        removeNativeBinariesLI(pkg);
+
         String cpuAbi = Build.CPU_ABI;
         try {
             int result = cachePackageSharedLibsForAbiLI(pkg, scanFile, cpuAbi);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9d5d035..4307cdc 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -17,7 +17,7 @@
 package com.android.server;
 
 import com.android.server.am.ActivityManagerService;
-import com.android.server.status.StatusBarService;
+import com.android.server.status.StatusBarManagerService;
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.SamplingProfilerIntegration;
 
@@ -206,7 +206,7 @@
         }
 
         DevicePolicyManagerService devicePolicy = null;
-        StatusBarService statusBar = null;
+        StatusBarManagerService statusBar = null;
         InputMethodManagerService imm = null;
         AppWidgetService appWidget = null;
         NotificationManagerService notification = null;
@@ -224,10 +224,10 @@
 
             try {
                 Slog.i(TAG, "Status Bar");
-                statusBar = new StatusBarService(context);
+                statusBar = new StatusBarManagerService(context);
                 ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting StatusBarService", e);
+                Slog.e(TAG, "Failure starting StatusBarManagerService", e);
             }
 
             try {
@@ -405,12 +405,6 @@
             }
 
             try {
-                com.android.server.status.StatusBarPolicy.installIcons(context, statusBar);
-            } catch (Throwable e) {
-                Slog.e(TAG, "Failure installing status bar icons", e);
-            }
-
-            try {
                 Slog.i(TAG, "DiskStats Service");
                 ServiceManager.addService("diskstats", new DiskStatsService(context));
             } catch (Throwable e) {
@@ -464,6 +458,7 @@
         }
 
         // These are needed to propagate to the runnable below.
+        final StatusBarManagerService statusBarF = statusBar;
         final BatteryService batteryF = battery;
         final ConnectivityService connectivityF = connectivity;
         final DockObserver dockF = dock;
@@ -485,6 +480,7 @@
             public void run() {
                 Slog.i(TAG, "Making services ready");
 
+                if (statusBarF != null) statusBarF.systemReady2();
                 if (batteryF != null) batteryF.systemReady();
                 if (connectivityF != null) connectivityF.systemReady();
                 if (dockF != null) dockF.systemReady();
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index 3606629..9493161 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -545,7 +545,7 @@
             mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);
         }
 
-        // Fear not: StatusBarService manages a list of requests to disable
+        // Fear not: StatusBarManagerService manages a list of requests to disable
         // features of the status bar; these are ORed together to form the
         // active disabled list. So if (for example) the device is locked and
         // the status bar should be totally disabled, the calls below will
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index 5eaadbc..d4133f3 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -39,6 +39,8 @@
 import android.util.Slog;
 
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -51,6 +53,9 @@
     // Set this to true to use debug default values.
     static final boolean DB = false;
 
+    // Set this to true to have the watchdog record kernel thread stacks when it fires
+    static final boolean RECORD_KERNEL_THREADS = true;
+
     static final int MONITOR = 2718;
     static final int GLOBAL_PSS = 2719;
 
@@ -850,6 +855,11 @@
             // The system's been hanging for a minute, another second or two won't hurt much.
             SystemClock.sleep(2000);
 
+            // Pull our own kernel thread stacks as well if we're configured for that
+            if (RECORD_KERNEL_THREADS) {
+                dumpKernelStackTraces();
+            }
+
             mActivity.addErrorToDropBox("watchdog", null, null, null, name, null, stack, null);
 
             // Only kill the process if the debugger is not attached.
@@ -864,4 +874,16 @@
             waitedHalf = false;
         }
     }
+
+    private File dumpKernelStackTraces() {
+        String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
+        if (tracesPath == null || tracesPath.length() == 0) {
+            return null;
+        }
+
+        native_dumpKernelStacks(tracesPath);
+        return new File(tracesPath);
+    }
+
+    private native void native_dumpKernelStacks(String tracesPath);
 }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8857c5f..c61f90e 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import com.android.internal.R;
+import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.AttributeCache;
 import com.android.server.IntentResolver;
@@ -39,10 +41,12 @@
 import android.app.IActivityWatcher;
 import android.app.IApplicationThread;
 import android.app.IInstrumentationWatcher;
+import android.app.INotificationManager;
 import android.app.IServiceConnection;
 import android.app.IThumbnailReceiver;
 import android.app.Instrumentation;
 import android.app.Notification;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.ResultInfo;
 import android.app.Service;
@@ -69,6 +73,7 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.net.Uri;
@@ -473,7 +478,8 @@
      * to become visible before completing whatever operation they are
      * supposed to do.
      */
-    final ArrayList mWaitingVisibleActivities = new ArrayList();
+    final ArrayList<HistoryRecord> mWaitingVisibleActivities
+            = new ArrayList<HistoryRecord>();
 
     /**
      * List of activities that are ready to be stopped, but waiting
@@ -501,7 +507,8 @@
      * for the previous activity to settle down before doing so.  It contains
      * HistoryRecord objects.
      */
-    final ArrayList mFinishingActivities = new ArrayList();
+    final ArrayList<HistoryRecord> mFinishingActivities
+            = new ArrayList<HistoryRecord>();
 
     /**
      * All of the applications we currently have running organized by name.
@@ -513,6 +520,11 @@
             = new ProcessMap<ProcessRecord>();
 
     /**
+     * The currently running heavy-weight process, if any.
+     */
+    ProcessRecord mHeavyWeightProcess = null;
+    
+    /**
      * The last time that various processes have crashed.
      */
     final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
@@ -726,21 +738,24 @@
      * that a single provider may be published under multiple names, so
      * there may be multiple entries here for a single one in mProvidersByClass.
      */
-    final HashMap mProvidersByName = new HashMap();
+    final HashMap<String, ContentProviderRecord> mProvidersByName
+            = new HashMap<String, ContentProviderRecord>();
 
     /**
      * All of the currently running global content providers.  Keys are a
      * string containing the provider's implementation class and values are a
      * ContentProviderRecord object containing the data about it.
      */
-    final HashMap mProvidersByClass = new HashMap();
+    final HashMap<String, ContentProviderRecord> mProvidersByClass
+            = new HashMap<String, ContentProviderRecord>();
 
     /**
      * List of content providers who have clients waiting for them.  The
      * application is currently being launched and the provider will be
      * removed from this list once it is published.
      */
-    final ArrayList mLaunchingProviders = new ArrayList();
+    final ArrayList<ContentProviderRecord> mLaunchingProviders
+            = new ArrayList<ContentProviderRecord>();
 
     /**
      * Global set of specific Uri permissions that have been granted.
@@ -1006,6 +1021,8 @@
     static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
     static final int KILL_APPLICATION_MSG = 22;
     static final int FINALIZE_PENDING_INTENT_MSG = 23;
+    static final int POST_HEAVY_NOTIFICATION_MSG = 24;
+    static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25;
 
     AlertDialog mUidAlert;
 
@@ -1235,6 +1252,62 @@
             case FINALIZE_PENDING_INTENT_MSG: {
                 ((PendingIntentRecord)msg.obj).completeFinalize();
             } break;
+            case POST_HEAVY_NOTIFICATION_MSG: {
+                INotificationManager inm = NotificationManager.getService();
+                if (inm == null) {
+                    return;
+                }
+                
+                HistoryRecord root = (HistoryRecord)msg.obj;
+                ProcessRecord process = root.app;
+                if (process == null) {
+                    return;
+                }
+                
+                try {
+                    Context context = mContext.createPackageContext(process.info.packageName, 0);
+                    String text = mContext.getString(R.string.heavy_weight_notification,
+                            context.getApplicationInfo().loadLabel(context.getPackageManager()));
+                    Notification notification = new Notification();
+                    notification.icon = com.android.internal.R.drawable.stat_sys_adb; //context.getApplicationInfo().icon;
+                    notification.when = 0;
+                    notification.flags = Notification.FLAG_ONGOING_EVENT;
+                    notification.tickerText = text;
+                    notification.defaults = 0; // please be quiet
+                    notification.sound = null;
+                    notification.vibrate = null;
+                    notification.setLatestEventInfo(context, text,
+                            mContext.getText(R.string.heavy_weight_notification_detail),
+                            PendingIntent.getActivity(mContext, 0, root.intent,
+                                    PendingIntent.FLAG_CANCEL_CURRENT));
+                    
+                    try {
+                        int[] outId = new int[1];
+                        inm.enqueueNotification("android", R.string.heavy_weight_notification,
+                                notification, outId);
+                    } catch (RuntimeException e) {
+                        Slog.w(ActivityManagerService.TAG,
+                                "Error showing notification for heavy-weight app", e);
+                    } catch (RemoteException e) {
+                    }
+                } catch (NameNotFoundException e) {
+                    Log.w(TAG, "Unable to create context for heavy notification", e);
+                }
+            } break;
+            case CANCEL_HEAVY_NOTIFICATION_MSG: {
+                INotificationManager inm = NotificationManager.getService();
+                if (inm == null) {
+                    return;
+                }
+                try {
+                    inm.cancelNotification("android",
+                            R.string.heavy_weight_notification);
+                } catch (RuntimeException e) {
+                    Slog.w(ActivityManagerService.TAG,
+                            "Error canceling notification for service", e);
+                } catch (RemoteException e) {
+                }
+            } break;
             }
         }
     };
@@ -1822,6 +1895,24 @@
                     System.identityHashCode(r),
                     r.info, r.icicle, results, newIntents, !andResume,
                     isNextTransitionForward());
+            
+            if ((app.info.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) {
+                // This may be a heavy-weight process!  Note that the package
+                // manager will ensure that only activity can run in the main
+                // process of the .apk, which is the only thing that will be
+                // considered heavy-weight.
+                if (app.processName.equals(app.info.packageName)) {
+                    if (mHeavyWeightProcess != null && mHeavyWeightProcess != app) {
+                        Log.w(TAG, "Starting new heavy weight process " + app
+                                + " when already running " + mHeavyWeightProcess);
+                    }
+                    mHeavyWeightProcess = app;
+                    Message msg = mHandler.obtainMessage(POST_HEAVY_NOTIFICATION_MSG);
+                    msg.obj = r;
+                    mHandler.sendMessage(msg);
+                }
+            }
+            
         } catch (RemoteException e) {
             if (r.launchFailed) {
                 // This is the second time we failed -- finish activity
@@ -3678,7 +3769,7 @@
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
 
-        final boolean componentSpecified = intent.getComponent() != null;
+        boolean componentSpecified = intent.getComponent() != null;
         
         // Don't modify the client's object!
         intent = new Intent(intent);
@@ -3728,6 +3819,74 @@
             
             final long origId = Binder.clearCallingIdentity();
             
+            if (aInfo != null &&
+                    (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) {
+                // This may be a heavy-weight process!  Check to see if we already
+                // have another, different heavy-weight process running.
+                if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
+                    if (mHeavyWeightProcess != null &&
+                            (mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
+                            !mHeavyWeightProcess.processName.equals(aInfo.processName))) {
+                        int realCallingPid = callingPid;
+                        int realCallingUid = callingUid;
+                        if (caller != null) {
+                            ProcessRecord callerApp = getRecordForAppLocked(caller);
+                            if (callerApp != null) {
+                                realCallingPid = callerApp.pid;
+                                realCallingUid = callerApp.info.uid;
+                            } else {
+                                Slog.w(TAG, "Unable to find app for caller " + caller
+                                      + " (pid=" + realCallingPid + ") when starting: "
+                                      + intent.toString());
+                                return START_PERMISSION_DENIED;
+                            }
+                        }
+                        
+                        IIntentSender target = getIntentSenderLocked(
+                                IActivityManager.INTENT_SENDER_ACTIVITY, "android",
+                                realCallingUid, null, null, 0, intent,
+                                resolvedType, PendingIntent.FLAG_CANCEL_CURRENT
+                                | PendingIntent.FLAG_ONE_SHOT);
+                        
+                        Intent newIntent = new Intent();
+                        if (requestCode >= 0) {
+                            // Caller is requesting a result.
+                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
+                        }
+                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
+                                new IntentSender(target));
+                        if (mHeavyWeightProcess.activities.size() > 0) {
+                            HistoryRecord hist = mHeavyWeightProcess.activities.get(0);
+                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
+                                    hist.packageName);
+                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
+                                    hist.task.taskId);
+                        }
+                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
+                                aInfo.packageName);
+                        newIntent.setFlags(intent.getFlags());
+                        newIntent.setClassName("android",
+                                HeavyWeightSwitcherActivity.class.getName());
+                        intent = newIntent;
+                        resolvedType = null;
+                        caller = null;
+                        callingUid = Binder.getCallingUid();
+                        callingPid = Binder.getCallingPid();
+                        componentSpecified = true;
+                        try {
+                            ResolveInfo rInfo =
+                                ActivityThread.getPackageManager().resolveIntent(
+                                        intent, null,
+                                        PackageManager.MATCH_DEFAULT_ONLY
+                                        | STOCK_PM_FLAGS);
+                            aInfo = rInfo != null ? rInfo.activityInfo : null;
+                        } catch (RemoteException e) {
+                            aInfo = null;
+                        }
+                    }
+                }
+            }
+            
             int res = startActivityLocked(caller, intent, resolvedType,
                     grantedUriPermissions, grantedMode, aInfo,
                     resultTo, resultWho, requestCode, callingPid, callingUid,
@@ -4316,6 +4475,40 @@
         }
     }
 
+    public final void finishHeavyWeightApp() {
+        if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
+                != PackageManager.PERMISSION_GRANTED) {
+            String msg = "Permission Denial: finishHeavyWeightApp() from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid()
+                    + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+        
+        synchronized(this) {
+            if (mHeavyWeightProcess == null) {
+                return;
+            }
+            
+            ArrayList<HistoryRecord> activities = new ArrayList<HistoryRecord>(
+                    mHeavyWeightProcess.activities);
+            for (int i=0; i<activities.size(); i++) {
+                HistoryRecord r = activities.get(i);
+                if (!r.finishing) {
+                    int index = indexOfTokenLocked(r);
+                    if (index >= 0) {
+                        finishActivityLocked(r, index, Activity.RESULT_CANCELED,
+                                null, "finish-heavy");
+                    }
+                }
+            }
+            
+            mHeavyWeightProcess = null;
+            mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG);
+        }
+    }
+    
     void sendActivityResultLocked(int callingUid, HistoryRecord r,
             String resultWho, int requestCode, int resultCode, Intent data) {
 
@@ -4513,6 +4706,10 @@
                 if (idx >= 0) {
                     r.app.activities.remove(idx);
                 }
+                if (mHeavyWeightProcess == r.app && r.app.activities.size() <= 0) {
+                    mHeavyWeightProcess = null;
+                    mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG);
+                }
                 if (r.persistent) {
                     decPersistentCountLocked(r.app);
                 }
@@ -5375,6 +5572,10 @@
             + "/" + uid + ")");
 
         mProcessNames.remove(name, uid);
+        if (mHeavyWeightProcess == app) {
+            mHeavyWeightProcess = null;
+            mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG);
+        }
         boolean needRestart = false;
         if (app.pid > 0 && app.pid != MY_PID) {
             int pid = app.pid;
@@ -5416,6 +5617,10 @@
             EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
                     app.processName);
             mProcessNames.remove(app.processName, app.info.uid);
+            if (mHeavyWeightProcess == app) {
+                mHeavyWeightProcess = null;
+                mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG);
+            }
             // Take care of any launching providers waiting for this process.
             checkAppInLaunchingProvidersLocked(app, true);
             // Take care of any services that are waiting for the process.
@@ -6101,57 +6306,66 @@
                         throw new SecurityException(msg);
                     }
                 }
+                
+                return getIntentSenderLocked(type, packageName, callingUid,
+                        token, resultWho, requestCode, intent, resolvedType, flags);
+                
             } catch (RemoteException e) {
                 throw new SecurityException(e);
             }
-            HistoryRecord activity = null;
-            if (type == INTENT_SENDER_ACTIVITY_RESULT) {
-                int index = indexOfTokenLocked(token);
-                if (index < 0) {
-                    return null;
-                }
-                activity = (HistoryRecord)mHistory.get(index);
-                if (activity.finishing) {
-                    return null;
-                }
+        }
+    }
+    
+    IIntentSender getIntentSenderLocked(int type,
+            String packageName, int callingUid, IBinder token, String resultWho,
+            int requestCode, Intent intent, String resolvedType, int flags) {
+        HistoryRecord activity = null;
+        if (type == INTENT_SENDER_ACTIVITY_RESULT) {
+            int index = indexOfTokenLocked(token);
+            if (index < 0) {
+                return null;
             }
-
-            final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
-            final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
-            final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
-            flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
-                    |PendingIntent.FLAG_UPDATE_CURRENT);
-
-            PendingIntentRecord.Key key = new PendingIntentRecord.Key(
-                    type, packageName, activity, resultWho,
-                    requestCode, intent, resolvedType, flags);
-            WeakReference<PendingIntentRecord> ref;
-            ref = mIntentSenderRecords.get(key);
-            PendingIntentRecord rec = ref != null ? ref.get() : null;
-            if (rec != null) {
-                if (!cancelCurrent) {
-                    if (updateCurrent) {
-                        rec.key.requestIntent.replaceExtras(intent);
-                    }
-                    return rec;
-                }
-                rec.canceled = true;
-                mIntentSenderRecords.remove(key);
+            activity = (HistoryRecord)mHistory.get(index);
+            if (activity.finishing) {
+                return null;
             }
-            if (noCreate) {
+        }
+
+        final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
+        final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
+        final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
+        flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
+                |PendingIntent.FLAG_UPDATE_CURRENT);
+
+        PendingIntentRecord.Key key = new PendingIntentRecord.Key(
+                type, packageName, activity, resultWho,
+                requestCode, intent, resolvedType, flags);
+        WeakReference<PendingIntentRecord> ref;
+        ref = mIntentSenderRecords.get(key);
+        PendingIntentRecord rec = ref != null ? ref.get() : null;
+        if (rec != null) {
+            if (!cancelCurrent) {
+                if (updateCurrent) {
+                    rec.key.requestIntent.replaceExtras(intent);
+                }
                 return rec;
             }
-            rec = new PendingIntentRecord(this, key, callingUid);
-            mIntentSenderRecords.put(key, rec.ref);
-            if (type == INTENT_SENDER_ACTIVITY_RESULT) {
-                if (activity.pendingResults == null) {
-                    activity.pendingResults
-                            = new HashSet<WeakReference<PendingIntentRecord>>();
-                }
-                activity.pendingResults.add(rec.ref);
-            }
+            rec.canceled = true;
+            mIntentSenderRecords.remove(key);
+        }
+        if (noCreate) {
             return rec;
         }
+        rec = new PendingIntentRecord(this, key, callingUid);
+        mIntentSenderRecords.put(key, rec.ref);
+        if (type == INTENT_SENDER_ACTIVITY_RESULT) {
+            if (activity.pendingResults == null) {
+                activity.pendingResults
+                        = new HashSet<WeakReference<PendingIntentRecord>>();
+            }
+            activity.pendingResults.add(rec.ref);
+        }
+        return rec;
     }
 
     public void cancelIntentSender(IIntentSender sender) {
@@ -6450,8 +6664,7 @@
 
         String name = uri.getAuthority();
         ProviderInfo pi = null;
-        ContentProviderRecord cpr
-                = (ContentProviderRecord)mProvidersByName.get(name);
+        ContentProviderRecord cpr = mProvidersByName.get(name);
         if (cpr != null) {
             pi = cpr.info;
         } else {
@@ -6648,8 +6861,7 @@
 
         final String authority = uri.getAuthority();
         ProviderInfo pi = null;
-        ContentProviderRecord cpr
-                = (ContentProviderRecord)mProvidersByName.get(authority);
+        ContentProviderRecord cpr = mProvidersByName.get(authority);
         if (cpr != null) {
             pi = cpr.info;
         } else {
@@ -6743,8 +6955,7 @@
 
             final String authority = uri.getAuthority();
             ProviderInfo pi = null;
-            ContentProviderRecord cpr
-                    = (ContentProviderRecord)mProvidersByName.get(authority);
+            ContentProviderRecord cpr = mProvidersByName.get(authority);
             if (cpr != null) {
                 pi = cpr.info;
             } else {
@@ -7752,8 +7963,7 @@
             for (int i=0; i<N; i++) {
                 ProviderInfo cpi =
                     (ProviderInfo)providers.get(i);
-                ContentProviderRecord cpr =
-                    (ContentProviderRecord)mProvidersByClass.get(cpi.name);
+                ContentProviderRecord cpr = mProvidersByClass.get(cpi.name);
                 if (cpr == null) {
                     cpr = new ContentProviderRecord(cpi, app.info);
                     mProvidersByClass.put(cpi.name, cpr);
@@ -7828,7 +8038,7 @@
             }
 
             // First check if this content provider has been published...
-            cpr = (ContentProviderRecord)mProvidersByName.get(name);
+            cpr = mProvidersByName.get(name);
             if (cpr != null) {
                 cpi = cpr.info;
                 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
@@ -7909,7 +8119,7 @@
                             "Attempt to launch content provider before system ready");
                 }
                 
-                cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
+                cpr = mProvidersByClass.get(cpi.name);
                 final boolean firstClass = cpr == null;
                 if (firstClass) {
                     try {
@@ -8043,7 +8253,7 @@
      */
     public void removeContentProvider(IApplicationThread caller, String name) {
         synchronized (this) {
-            ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
+            ContentProviderRecord cpr = mProvidersByName.get(name);
             if(cpr == null) {
                 // remove from mProvidersByClass
                 if (DEBUG_PROVIDER) Slog.v(TAG, name +
@@ -8057,8 +8267,7 @@
                         " when removing content provider " + name);
             }
             //update content provider record entry info
-            ContentProviderRecord localCpr = (ContentProviderRecord)
-                    mProvidersByClass.get(cpr.info.name);
+            ContentProviderRecord localCpr = mProvidersByClass.get(cpr.info.name);
             if (DEBUG_PROVIDER) Slog.v(TAG, "Removing provider requested by "
                     + r.info.processName + " from process "
                     + localCpr.appInfo.processName);
@@ -8082,7 +8291,7 @@
 
     private void removeContentProviderExternal(String name) {
         synchronized (this) {
-            ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
+            ContentProviderRecord cpr = mProvidersByName.get(name);
             if(cpr == null) {
                 //remove from mProvidersByClass
                 if(localLOGV) Slog.v(TAG, name+" content provider not found in providers list");
@@ -8090,7 +8299,7 @@
             }
 
             //update content provider record entry info
-            ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
+            ContentProviderRecord localCpr = mProvidersByClass.get(cpr.info.name);
             localCpr.externals--;
             if (localCpr.externals < 0) {
                 Slog.e(TAG, "Externals < 0 for content provider " + localCpr);
@@ -8122,8 +8331,7 @@
                 if (src == null || src.info == null || src.provider == null) {
                     continue;
                 }
-                ContentProviderRecord dst =
-                    (ContentProviderRecord)r.pubProviders.get(src.info.name);
+                ContentProviderRecord dst = r.pubProviders.get(src.info.name);
                 if (dst != null) {
                     mProvidersByClass.put(dst.info.name, dst);
                     String names[] = dst.info.authority.split(";");
@@ -9038,9 +9246,9 @@
         if (app.services.size() != 0) {
             // Any services running in the application need to be placed
             // back in the pending list.
-            Iterator it = app.services.iterator();
+            Iterator<ServiceRecord> it = app.services.iterator();
             while (it.hasNext()) {
-                ServiceRecord sr = (ServiceRecord)it.next();
+                ServiceRecord sr = it.next();
                 sr.crashCount++;
             }
         }
@@ -9485,6 +9693,8 @@
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
                     } else if (adj >= VISIBLE_APP_ADJ) {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+                    } else if (app == mHeavyWeightProcess) {
+                        currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_HEAVY_WEIGHT;
                     } else {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
                     }
@@ -9860,6 +10070,9 @@
 
         pw.println(" ");
         pw.println("  mHomeProcess: " + mHomeProcess);
+        if (mHeavyWeightProcess != null) {
+            pw.println("  mHeavyWeightProcess: " + mHeavyWeightProcess);
+        }
         pw.println("  mConfiguration: " + mConfiguration);
         pw.println("  mConfigWillChange: " + mConfigWillChange);
         pw.println("  mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
@@ -10121,10 +10334,11 @@
             if (mProvidersByClass.size() > 0) {
                 if (needSep) pw.println(" ");
                 pw.println("  Published content providers (by class):");
-                Iterator it = mProvidersByClass.entrySet().iterator();
+                Iterator<Map.Entry<String, ContentProviderRecord>> it
+                        = mProvidersByClass.entrySet().iterator();
                 while (it.hasNext()) {
-                    Map.Entry e = (Map.Entry)it.next();
-                    ContentProviderRecord r = (ContentProviderRecord)e.getValue();
+                    Map.Entry<String, ContentProviderRecord> e = it.next();
+                    ContentProviderRecord r = e.getValue();
                     pw.print("  * "); pw.println(r);
                     r.dump(pw, "    ");
                 }
@@ -10134,10 +10348,11 @@
             if (mProvidersByName.size() > 0) {
                 pw.println(" ");
                 pw.println("  Authority to provider mappings:");
-                Iterator it = mProvidersByName.entrySet().iterator();
+                Iterator<Map.Entry<String, ContentProviderRecord>> it
+                        = mProvidersByName.entrySet().iterator();
                 while (it.hasNext()) {
-                    Map.Entry e = (Map.Entry)it.next();
-                    ContentProviderRecord r = (ContentProviderRecord)e.getValue();
+                    Map.Entry<String, ContentProviderRecord> e = it.next();
+                    ContentProviderRecord r = e.getValue();
                     pw.print("  "); pw.print(e.getKey()); pw.print(": ");
                             pw.println(r);
                 }
@@ -10370,9 +10585,9 @@
             // XXX we are letting the client link to the service for
             // death notifications.
             if (app.services.size() > 0) {
-                Iterator it = app.services.iterator();
+                Iterator<ServiceRecord> it = app.services.iterator();
                 while (it.hasNext()) {
-                    ServiceRecord r = (ServiceRecord)it.next();
+                    ServiceRecord r = it.next();
                     if (r.connections.size() > 0) {
                         Iterator<ConnectionRecord> jt
                                 = r.connections.values().iterator();
@@ -10407,9 +10622,9 @@
         if (app.services.size() != 0) {
             // Any services running in the application need to be placed
             // back in the pending list.
-            Iterator it = app.services.iterator();
+            Iterator<ServiceRecord> it = app.services.iterator();
             while (it.hasNext()) {
-                ServiceRecord sr = (ServiceRecord)it.next();
+                ServiceRecord sr = it.next();
                 synchronized (sr.stats.getBatteryStats()) {
                     sr.stats.stopLaunchedLocked();
                 }
@@ -10548,9 +10763,9 @@
         
         // Remove published content providers.
         if (!app.pubProviders.isEmpty()) {
-            Iterator it = app.pubProviders.values().iterator();
+            Iterator<ContentProviderRecord> it = app.pubProviders.values().iterator();
             while (it.hasNext()) {
-                ContentProviderRecord cpr = (ContentProviderRecord)it.next();
+                ContentProviderRecord cpr = it.next();
                 cpr.provider = null;
                 cpr.app = null;
 
@@ -10642,6 +10857,10 @@
             if (DEBUG_PROCESSES) Slog.v(TAG,
                     "Removing non-persistent process during cleanup: " + app);
             mProcessNames.remove(app.processName, app.info.uid);
+            if (mHeavyWeightProcess == app) {
+                mHeavyWeightProcess = null;
+                mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG);
+            }
         } else if (!app.removed) {
             // This app is persistent, so we need to keep its record around.
             // If it is not already on the pending app list, add it there
@@ -10683,8 +10902,7 @@
         int NL = mLaunchingProviders.size();
         boolean restart = false;
         for (int i=0; i<NL; i++) {
-            ContentProviderRecord cpr = (ContentProviderRecord)
-                    mLaunchingProviders.get(i);
+            ContentProviderRecord cpr = mLaunchingProviders.get(i);
             if (cpr.launchingApp == app) {
                 if (!alwaysBad && !app.bad) {
                     restart = true;
@@ -11601,7 +11819,7 @@
 
     public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
         boolean anyForeground = false;
-        for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
+        for (ServiceRecord sr : proc.services) {
             if (sr.isForeground) {
                 anyForeground = true;
                 break;
@@ -13824,6 +14042,11 @@
             adj = FOREGROUND_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "instrumentation";
+        } else if (app == mHeavyWeightProcess) {
+            // We don't want to kill the current heavy-weight process.
+            adj = FOREGROUND_APP_ADJ;
+            schedGroup = Process.THREAD_GROUP_DEFAULT;
+            app.adjType = "heavy";
         } else if (app.persistentActivities > 0) {
             // Special persistent activities...  shouldn't be used these days.
             adj = FOREGROUND_APP_ADJ;
@@ -13867,7 +14090,7 @@
             app.adjType = "bg-activities";
             N = app.activities.size();
             for (int j=0; j<N; j++) {
-                if (((HistoryRecord)app.activities.get(j)).visible) {
+                if (app.activities.get(j).visible) {
                     // This app has a visible activity!
                     app.hidden = false;
                     adj = VISIBLE_APP_ADJ;
@@ -13910,9 +14133,9 @@
             final long now = SystemClock.uptimeMillis();
             // This process is more important if the top activity is
             // bound to the service.
-            Iterator jt = app.services.iterator();
+            Iterator<ServiceRecord> jt = app.services.iterator();
             while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
-                ServiceRecord s = (ServiceRecord)jt.next();
+                ServiceRecord s = jt.next();
                 if (s.startRequested) {
                     if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
                         // This service has seen some activity within
@@ -13965,7 +14188,7 @@
                                 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
                                         .REASON_SERVICE_IN_USE;
                                 app.adjSource = cr.binding.client;
-                                app.adjTarget = s.serviceInfo.name;
+                                app.adjTarget = s.name;
                             }
                             if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
                                 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
@@ -13987,7 +14210,7 @@
                             app.adjTypeCode = ActivityManager.RunningAppProcessInfo
                                     .REASON_SERVICE_IN_USE;
                             app.adjSource = a;
-                            app.adjTarget = s.serviceInfo.name;
+                            app.adjTarget = s.name;
                         }
                     }
                 }
@@ -14007,10 +14230,10 @@
 
         if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
                 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
-            Iterator jt = app.pubProviders.values().iterator();
+            Iterator<ContentProviderRecord> jt = app.pubProviders.values().iterator();
             while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
                     || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
-                ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
+                ContentProviderRecord cpr = jt.next();
                 if (cpr.clients.size() != 0) {
                     Iterator<ProcessRecord> kt = cpr.clients.iterator();
                     while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
@@ -14039,7 +14262,7 @@
                             app.adjTypeCode = ActivityManager.RunningAppProcessInfo
                                     .REASON_PROVIDER_IN_USE;
                             app.adjSource = client;
-                            app.adjTarget = cpr.info.name;
+                            app.adjTarget = cpr.name;
                         }
                         if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
                             schedGroup = Process.THREAD_GROUP_DEFAULT;
@@ -14055,7 +14278,7 @@
                         schedGroup = Process.THREAD_GROUP_DEFAULT;
                         app.hidden = false;
                         app.adjType = "provider";
-                        app.adjTarget = cpr.info.name;
+                        app.adjTarget = cpr.name;
                     }
                 }
             }
@@ -14491,7 +14714,7 @@
                     if (Config.LOGV) Slog.v(
                         TAG, "Looking to quit " + app.processName);
                     for (j=0; j<NUMA && canQuit; j++) {
-                        HistoryRecord r = (HistoryRecord)app.activities.get(j);
+                        HistoryRecord r = app.activities.get(j);
                         if (Config.LOGV) Slog.v(
                             TAG, "  " + r.intent.getComponent().flattenToShortString()
                             + ": frozen=" + r.haveState + ", visible=" + r.visible);
@@ -14501,7 +14724,7 @@
                     if (canQuit) {
                         // Finish all of the activities, and then the app itself.
                         for (j=0; j<NUMA; j++) {
-                            HistoryRecord r = (HistoryRecord)app.activities.get(j);
+                            HistoryRecord r = app.activities.get(j);
                             if (!r.finishing) {
                                 destroyActivityLocked(r, false);
                             }
diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java
index c764635..44c9742 100644
--- a/services/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/java/com/android/server/am/ContentProviderRecord.java
@@ -17,6 +17,7 @@
 package com.android.server.am;
 
 import android.app.IActivityManager.ContentProviderHolder;
+import android.content.ComponentName;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ProviderInfo;
 import android.os.Process;
@@ -29,6 +30,7 @@
     final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
     final int uid;
     final ApplicationInfo appInfo;
+    final ComponentName name;
     int externals;     // number of non-framework processes supported by this provider
     ProcessRecord app; // if non-null, hosting application
     ProcessRecord launchingApp; // if non-null, waiting for this app to be launched.
@@ -38,6 +40,7 @@
         super(_info);
         uid = ai.uid;
         appInfo = ai;
+        name = new ComponentName(_info.packageName, _info.name);
         noReleaseNeeded = uid == 0 || uid == Process.SYSTEM_UID;
     }
 
@@ -45,6 +48,7 @@
         super(cpr.info);
         uid = cpr.uid;
         appInfo = cpr.appInfo;
+        name = cpr.name;
         noReleaseNeeded = cpr.noReleaseNeeded;
     }
 
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index f49a182..9dda1df 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -28,7 +28,6 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.util.PrintWriterPrinter;
 
 import java.io.PrintWriter;
@@ -45,7 +44,7 @@
     final ApplicationInfo info; // all about the first app in the process
     final String processName;   // name of the process
     // List of packages running in the process
-    final HashSet<String> pkgList = new HashSet();
+    final HashSet<String> pkgList = new HashSet<String>();
     IApplicationThread thread;  // the actual proc...  may be null only if
                                 // 'persistent' is true (in which case we
                                 // are in the process of launching the app)
@@ -87,9 +86,9 @@
     Object adjTarget;           // Debugging: target component impacting oom_adj.
     
     // contains HistoryRecord objects
-    final ArrayList activities = new ArrayList();
+    final ArrayList<HistoryRecord> activities = new ArrayList<HistoryRecord>();
     // all ServiceRecord running in this process
-    final HashSet services = new HashSet();
+    final HashSet<ServiceRecord> services = new HashSet<ServiceRecord>();
     // services that are currently executing code (need to remain foreground).
     final HashSet<ServiceRecord> executingServices
              = new HashSet<ServiceRecord>();
@@ -99,7 +98,8 @@
     // all IIntentReceivers that are registered from this process.
     final HashSet<ReceiverList> receivers = new HashSet<ReceiverList>();
     // class (String) -> ContentProviderRecord
-    final HashMap pubProviders = new HashMap(); 
+    final HashMap<String, ContentProviderRecord> pubProviders
+            = new HashMap<String, ContentProviderRecord>(); 
     // All ContentProviderRecord process is using
     final HashMap<ContentProviderRecord, Integer> conProviders
             = new HashMap<ContentProviderRecord, Integer>(); 
@@ -128,7 +128,6 @@
     ComponentName errorReportReceiver;
 
     void dump(PrintWriter pw, String prefix) {
-        long now = SystemClock.uptimeMillis();
         if (info.className != null) {
             pw.print(prefix); pw.print("class="); pw.println(info.className);
         }
@@ -249,7 +248,7 @@
     public boolean isInterestingToUserLocked() {
         final int size = activities.size();
         for (int i = 0 ; i < size ; i++) {
-            HistoryRecord r = (HistoryRecord) activities.get(i);
+            HistoryRecord r = activities.get(i);
             if (r.isInterestingToUserLocked()) {
                 return true;
             }
@@ -261,7 +260,7 @@
         int i = activities.size();
         while (i > 0) {
             i--;
-            ((HistoryRecord)activities.get(i)).stopFreezingScreenLocked(true);
+            activities.get(i).stopFreezingScreenLocked(true);
         }
     }
     
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index b43b86c..b29f875 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -98,6 +98,7 @@
     private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
     private static final String DNS_DEFAULT_SERVER2 = "4.2.2.2";
 
+    // resampled each time we turn on tethering - used as cache for settings/config-val
     private boolean mDunRequired;  // configuration info - must use DUN apn on 3g
 
     private HierarchicalStateMachine mTetherMasterSM;
@@ -157,8 +158,7 @@
             mDhcpRange[2] = DHCP_DEFAULT_RANGE2_START;
             mDhcpRange[3] = DHCP_DEFAULT_RANGE2_STOP;
         }
-        mDunRequired = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_tether_dun_required);
+        mDunRequired = false; // resample when we turn on
 
         mTetherableUsbRegexs = context.getResources().getStringArray(
                 com.android.internal.R.array.config_tether_usb_regexs);
@@ -555,7 +555,11 @@
     }
 
     public boolean isDunRequired() {
-        return mDunRequired;
+        boolean defaultVal = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_tether_dun_required);
+        boolean result = (Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.TETHER_DUN_REQUIRED, (defaultVal ? 1 : 0)) == 1);
+        return result;
     }
 
     public String[] getTetheredIfaces() {
@@ -1263,6 +1267,7 @@
                 boolean retValue = true;
                 switch (message.what) {
                     case CMD_TETHER_MODE_REQUESTED:
+                        mDunRequired = isDunRequired();
                         TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
                         Log.d(TAG, "Tether Mode requested by " + who.toString());
                         mNotifyList.add(who);
diff --git a/services/java/com/android/server/status/IconData.java b/services/java/com/android/server/status/IconData.java
deleted file mode 100644
index fd226f9..0000000
--- a/services/java/com/android/server/status/IconData.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.status;
-
-import android.util.Slog;
-
-public class IconData {
-    /**
-     * Indicates ths item represents a piece of text.
-     */
-    public static final int TEXT = 1;
-    
-    /**
-     * Indicates ths item represents an icon.
-     */
-    public static final int ICON = 2;
-
-    /**
-     * The type of this item. One of TEXT, ICON, or LEVEL_ICON.
-     */
-    public int type;
-
-    /**
-     * The slot that this icon will be in if it is not a notification
-     */
-    public String slot;
-
-    /**
-     * The package containting the icon to draw for this item. Valid if this is
-     * an ICON type.
-     */
-    public String iconPackage;
-    
-    /**
-     * The icon to draw for this item. Valid if this is an ICON type.
-     */
-    public int iconId;
-    
-    /**
-     * The level associated with the icon. Valid if this is a LEVEL_ICON type.
-     */
-    public int iconLevel;
-    
-    /**
-     * The "count" number.
-     */
-    public int number;
-
-    /**
-     * The text associated with the icon. Valid if this is a TEXT type.
-     */
-    public CharSequence text;
-
-    private IconData() {
-    }
-
-    public static IconData makeIcon(String slot,
-            String iconPackage, int iconId, int iconLevel, int number) {
-        IconData data = new IconData();
-        data.type = ICON;
-        data.slot = slot;
-        data.iconPackage = iconPackage;
-        data.iconId = iconId;
-        data.iconLevel = iconLevel;
-        data.number = number;
-        return data;
-    }
-    
-    public static IconData makeText(String slot, CharSequence text) {
-        IconData data = new IconData();
-        data.type = TEXT;
-        data.slot = slot;
-        data.text = text;
-        return data;
-    }
-
-    public void copyFrom(IconData that) {
-        this.type = that.type;
-        this.slot = that.slot;
-        this.iconPackage = that.iconPackage;
-        this.iconId = that.iconId;
-        this.iconLevel = that.iconLevel;
-        this.number = that.number;
-        this.text = that.text; // should we clone this?
-    }
-
-    public IconData clone() {
-        IconData that = new IconData();
-        that.copyFrom(this);
-        return that;
-    }
-
-    public String toString() {
-        if (this.type == TEXT) {
-            return "IconData(slot=" + (this.slot != null ? "'" + this.slot + "'" : "null")
-                    + " text='" + this.text + "')"; 
-        }
-        else if (this.type == ICON) {
-            return "IconData(slot=" + (this.slot != null ? "'" + this.slot + "'" : "null")
-                    + " package=" + this.iconPackage
-                    + " iconId=" + Integer.toHexString(this.iconId)
-                    + " iconLevel=" + this.iconLevel + ")"; 
-        }
-        else {
-            return "IconData(type=" + type + ")";
-        }
-    }
-}
diff --git a/services/java/com/android/server/status/NotificationData.java b/services/java/com/android/server/status/NotificationData.java
deleted file mode 100644
index 71f01ca..0000000
--- a/services/java/com/android/server/status/NotificationData.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.status;
-
-import android.app.PendingIntent;
-import android.widget.RemoteViews;
-
-public class NotificationData {
-    public String pkg;
-    public String tag;
-    public int id;
-    public CharSequence tickerText;
-
-    public long when;
-    public boolean ongoingEvent;
-    public boolean clearable;
-
-    public RemoteViews contentView;
-    public PendingIntent contentIntent;
-
-    public PendingIntent deleteIntent;
-
-    public String toString() {
-        return "NotificationData(package=" + pkg + " id=" + id + " tickerText=" + tickerText
-                + " ongoingEvent=" + ongoingEvent + " contentIntent=" + contentIntent
-                + " deleteIntent=" + deleteIntent
-                + " clearable=" + clearable
-                + " contentView=" + contentView + " when=" + when + ")";
-    }
-}
diff --git a/services/java/com/android/server/status/NotificationViewList.java b/services/java/com/android/server/status/NotificationViewList.java
deleted file mode 100644
index 1bb56a7..0000000
--- a/services/java/com/android/server/status/NotificationViewList.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.status;
-
-import android.os.IBinder;
-import android.util.Slog;
-import android.view.View;
-import java.util.ArrayList;
-
-class NotificationViewList {
-    private ArrayList<StatusBarNotification> mOngoing = new ArrayList();
-    private ArrayList<StatusBarNotification> mLatest = new ArrayList();
-
-    NotificationViewList() {
-    }
-
-    private static final int indexInList(ArrayList<StatusBarNotification> list, NotificationData n){
-        final int N = list.size();
-        for (int i=0; i<N; i++) {
-            StatusBarNotification that = list.get(i);
-            if (that.data == n) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    int getIconIndex(NotificationData n) {
-        final int ongoingSize = mOngoing.size();
-        final int latestSize = mLatest.size();
-        if (n.ongoingEvent) {
-            int index = indexInList(mOngoing, n);
-            if (index >= 0) {
-                return latestSize + index + 1;
-            } else {
-                return -1;
-            }
-        } else {
-            return indexInList(mLatest, n) + 1;
-        }
-    }
-
-    void remove(StatusBarNotification notification) {
-        NotificationData n = notification.data;
-        int index;
-        index = indexInList(mOngoing, n);
-        if (index >= 0) {
-            mOngoing.remove(index);
-            return;
-        }
-        index = indexInList(mLatest, n);
-        if (index >= 0) {
-            mLatest.remove(index);
-            return;
-        }
-    }
-
-    ArrayList<StatusBarNotification> notificationsForPackage(String packageName) {
-        ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>();
-        int N = mOngoing.size();
-        for (int i=0; i<N; i++) {
-            if (matchPackage(mOngoing.get(i), packageName)) {
-                list.add(mOngoing.get(i));
-            }
-        }
-        N = mLatest.size();
-        for (int i=0; i<N; i++) {
-            if (matchPackage(mLatest.get(i), packageName)) {
-                list.add(mLatest.get(i));
-            }
-        }
-        return list;
-    }
-    
-    private final boolean matchPackage(StatusBarNotification snb, String packageName) {
-        if (snb.data.contentIntent != null) {
-            if (snb.data.contentIntent.getTargetPackage().equals(packageName)) {
-                return true;
-            }
-        } else if (snb.data.pkg != null && snb.data.pkg.equals(packageName)) {
-            return true;
-        }
-        return false;
-    }
-    
-    private static final int indexForKey(ArrayList<StatusBarNotification> list, IBinder key) {
-        final int N = list.size();
-        for (int i=0; i<N; i++) {
-            if (list.get(i).key == key) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    StatusBarNotification get(IBinder key) {
-        int index;
-        index = indexForKey(mOngoing, key);
-        if (index >= 0) {
-            return mOngoing.get(index);
-        }
-        index = indexForKey(mLatest, key);
-        if (index >= 0) {
-            return mLatest.get(index);
-        }
-        return null;
-    }
-
-    // gets the index of the notification's view in its expanded parent view
-    int getExpandedIndex(StatusBarNotification notification) {
-        ArrayList<StatusBarNotification> list = notification.data.ongoingEvent ? mOngoing : mLatest;
-        final IBinder key = notification.key;
-        int index = 0;
-        // (the view order is backwards from this list order)
-        for (int i=list.size()-1; i>=0; i--) {
-            StatusBarNotification item = list.get(i);
-            if (item.key == key) {
-                return index;
-            }
-            if (item.view != null) {
-                index++;
-            }
-        }
-        Slog.e(StatusBarService.TAG, "Couldn't find notification in NotificationViewList.");
-        Slog.e(StatusBarService.TAG, "notification=" + notification);
-        dump(notification);
-        return 0;
-    }
-
-    void clearViews() {
-        int N = mOngoing.size();
-        for (int i=0; i<N; i++) {
-            mOngoing.get(i).view = null;
-        }
-        N = mLatest.size();
-        for (int i=0; i<N; i++) {
-            mLatest.get(i).view = null;
-        }
-    }
-    
-    int ongoingCount() {
-        return mOngoing.size();
-    }
-
-    int latestCount() {
-        return mLatest.size();
-    }
-
-    StatusBarNotification getOngoing(int index) {
-        return mOngoing.get(index);
-    }
-
-    StatusBarNotification getLatest(int index) {
-        return mLatest.get(index);
-    }
-
-    int size() {
-        return mOngoing.size() + mLatest.size();
-    }
-
-    void add(StatusBarNotification notification) {
-        if (StatusBarService.SPEW) {
-            Slog.d(StatusBarService.TAG, "before add NotificationViewList"
-                    + " notification.data.ongoingEvent=" + notification.data.ongoingEvent);
-            dump(notification);
-        }
-
-        ArrayList<StatusBarNotification> list = notification.data.ongoingEvent ? mOngoing : mLatest;
-        long when = notification.data.when;
-        final int N = list.size();
-        int index = N;
-        for (int i=0; i<N; i++) {
-            StatusBarNotification that = list.get(i);
-            if (that.data.when > when) {
-                index = i;
-                break;
-            }
-        }
-        list.add(index, notification);
-
-        if (StatusBarService.SPEW) {
-            Slog.d(StatusBarService.TAG, "after add NotificationViewList index=" + index);
-            dump(notification);
-        }
-    }
-
-    void dump(StatusBarNotification notification) {
-        if (StatusBarService.SPEW) {
-            boolean showTime = false;
-            String s = "";
-            for (int i=0; i<mOngoing.size(); i++) {
-                StatusBarNotification that = mOngoing.get(i);
-                if (that.key == notification.key) {
-                    s += "[";
-                }
-                if (showTime) {
-                    s += that.data.when;
-                } else {
-                    s += that.data.pkg + "/" + that.data.id + "/" + that.view;
-                }
-                if (that.key == notification.key) {
-                    s += "]";
-                }
-                s += " ";
-            }
-            Slog.d(StatusBarService.TAG, "NotificationViewList ongoing: " + s);
-
-            s = "";
-            for (int i=0; i<mLatest.size(); i++) {
-                StatusBarNotification that = mLatest.get(i);
-                if (that.key == notification.key) {
-                    s += "[";
-                }
-                if (showTime) {
-                    s += that.data.when;
-                } else {
-                    s += that.data.pkg + "/" + that.data.id + "/" + that.view;
-                }
-                if (that.key == notification.key) {
-                    s += "]";
-                }
-                s += " ";
-            }
-            Slog.d(StatusBarService.TAG, "NotificationViewList latest:  " + s);
-        }
-    }
-
-    StatusBarNotification get(View view) {
-        int N = mOngoing.size();
-        for (int i=0; i<N; i++) {
-            StatusBarNotification notification = mOngoing.get(i);
-            View v = notification.view;
-            if (v == view) {
-                return notification;
-            }
-        }
-        N = mLatest.size();
-        for (int i=0; i<N; i++) {
-            StatusBarNotification notification = mLatest.get(i);
-            View v = notification.view;
-            if (v == view) {
-                return notification;
-            }
-        }
-        return null;
-    }
-
-    void update(StatusBarNotification notification) {
-        remove(notification);
-        add(notification);
-    }
-
-    boolean hasClearableItems() {
-        int N = mLatest.size();
-        for (int i=0; i<N; i++) {
-            if (mLatest.get(i).data.clearable) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/services/java/com/android/server/status/StatusBarIcon.java b/services/java/com/android/server/status/StatusBarIcon.java
deleted file mode 100644
index f77b550..0000000
--- a/services/java/com/android/server/status/StatusBarIcon.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.status;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
-import android.util.Slog;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-class StatusBarIcon {
-    // TODO: get this from a resource
-    private static final int ICON_GAP = 8;
-    private static final int ICON_WIDTH = 25;
-    private static final int ICON_HEIGHT = 25;
-
-    public View view;
-
-    IconData mData;
-    
-    private TextView mTextView;
-    private AnimatedImageView mImageView;
-    private TextView mNumberView;
-
-    public StatusBarIcon(Context context, IconData data, ViewGroup parent) {
-        mData = data.clone();
-
-        switch (data.type) {
-            case IconData.TEXT: {
-                TextView t;
-                t = new TextView(context, null, com.android.internal.R.style.TextAppearance_StatusBar_Icon);
-                mTextView = t;
-                LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
-                        LinearLayout.LayoutParams.WRAP_CONTENT,
-                        LinearLayout.LayoutParams.MATCH_PARENT);
-                t.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
-                t.setPadding(6, 0, 0, 0);
-                t.setLayoutParams(layoutParams);
-                t.setText(data.text);
-                this.view = t;
-                break;
-            }
-
-            case IconData.ICON: {
-                // container
-                LayoutInflater inflater = (LayoutInflater)context.getSystemService(
-                                                Context.LAYOUT_INFLATER_SERVICE);
-                View v = inflater.inflate(com.android.internal.R.layout.status_bar_icon, parent, false);
-                this.view = v;
-
-                // icon
-                AnimatedImageView im = (AnimatedImageView)v.findViewById(com.android.internal.R.id.image);
-                im.setImageDrawable(getIcon(context, data));
-                im.setImageLevel(data.iconLevel);
-                mImageView = im;
-
-                // number
-                TextView nv = (TextView)v.findViewById(com.android.internal.R.id.number);
-                mNumberView = nv;
-                if (data.number > 0) {
-                    nv.setText("" + data.number);
-                    nv.setVisibility(View.VISIBLE);
-                } else {
-                    nv.setVisibility(View.GONE);
-                }
-                break;
-            }
-        }
-    }
-
-    public void update(Context context, IconData data) throws StatusBarException {
-        if (mData.type != data.type) {
-            throw new StatusBarException("status bar entry type can't change");
-        }
-        switch (data.type) {
-        case IconData.TEXT:
-            if (!TextUtils.equals(mData.text, data.text)) {
-                TextView tv = mTextView;
-                tv.setText(data.text);
-            }
-            break;
-        case IconData.ICON:
-            if (((mData.iconPackage != null && data.iconPackage != null)
-                        && !mData.iconPackage.equals(data.iconPackage))
-                    || mData.iconId != data.iconId
-                    || mData.iconLevel != data.iconLevel) {
-                ImageView im = mImageView;
-                im.setImageDrawable(getIcon(context, data));
-                im.setImageLevel(data.iconLevel);
-            }
-            if (mData.number != data.number) {
-                TextView nv = mNumberView;
-                if (data.number > 0) {
-                    nv.setText("" + data.number);
-                } else {
-                    nv.setText("");
-                }
-            }
-            break;
-        }
-        mData.copyFrom(data);
-    }
-
-    public void update(int number) {
-        if (mData.number != number) {
-            TextView nv = mNumberView;
-            if (number > 0) {
-                nv.setText("" + number);
-            } else {
-                nv.setText("");
-            }
-        }
-        mData.number = number;
-    }
-
-
-    /**
-     * Returns the right icon to use for this item, respecting the iconId and
-     * iconPackage (if set)
-     * 
-     * @param context Context to use to get resources if iconPackage is not set
-     * @return Drawable for this item, or null if the package or item could not
-     *         be found
-     */
-    static Drawable getIcon(Context context, IconData data) {
-
-        Resources r = null;
-
-        if (data.iconPackage != null) {
-            try {
-                r = context.getPackageManager().getResourcesForApplication(data.iconPackage);
-            } catch (PackageManager.NameNotFoundException ex) {
-                Slog.e(StatusBarService.TAG, "Icon package not found: " + data.iconPackage, ex);
-                return null;
-            }
-        } else {
-            r = context.getResources();
-        }
-
-        if (data.iconId == 0) {
-            Slog.w(StatusBarService.TAG, "No icon ID for slot " + data.slot);
-            return null;
-        }
-        
-        try {
-            return r.getDrawable(data.iconId);
-        } catch (RuntimeException e) {
-            Slog.w(StatusBarService.TAG, "Icon not found in "
-                  + (data.iconPackage != null ? data.iconId : "<system>")
-                  + ": " + Integer.toHexString(data.iconId));
-        }
-
-        return null;
-    }
-
-    int getNumber() {
-        return mData.number;
-    }
-}
-
diff --git a/services/java/com/android/server/status/StatusBarManagerService.java b/services/java/com/android/server/status/StatusBarManagerService.java
new file mode 100644
index 0000000..0af1ebb
--- /dev/null
+++ b/services/java/com/android/server/status/StatusBarManagerService.java
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.status;
+
+import android.app.PendingIntent;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.util.Slog;
+
+import com.android.internal.statusbar.IStatusBar;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.StatusBarNotification;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * A note on locking:  We rely on the fact that calls onto mBar are oneway or
+ * if they are local, that they just enqueue messages to not deadlock.
+ */
+public class StatusBarManagerService extends IStatusBarService.Stub
+{
+    static final String TAG = "StatusBarManagerService";
+    static final boolean SPEW = true;
+
+    public static final String ACTION_STATUSBAR_START
+            = "com.android.internal.policy.statusbar.START";
+
+    final Context mContext;
+    Handler mHandler = new Handler();
+    NotificationCallbacks mNotificationCallbacks;
+    volatile IStatusBar mBar;
+    StatusBarIconList mIcons = new StatusBarIconList();
+    HashMap<IBinder,StatusBarNotification> mNotifications
+            = new HashMap<IBinder,StatusBarNotification>();
+
+    // for disabling the status bar
+    ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
+    int mDisabled = 0;
+
+    private class DisableRecord implements IBinder.DeathRecipient {
+        String pkg;
+        int what;
+        IBinder token;
+
+        public void binderDied() {
+            Slog.i(TAG, "binder died for pkg=" + pkg);
+            disable(0, token, pkg);
+            token.unlinkToDeath(this, 0);
+        }
+    }
+
+    public interface NotificationCallbacks {
+        void onSetDisabled(int status);
+        void onClearAll();
+        void onNotificationClick(String pkg, String tag, int id);
+        void onPanelRevealed();
+    }
+
+    /**
+     * Construct the service, add the status bar view to the window manager
+     */
+    public StatusBarManagerService(Context context) {
+        mContext = context;
+
+        final Resources res = context.getResources();
+        mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.status_bar_icon_order));
+    }
+
+    public void setNotificationCallbacks(NotificationCallbacks listener) {
+        mNotificationCallbacks = listener;
+    }
+
+    // ================================================================================
+    // Constructing the view
+    // ================================================================================
+
+    public void systemReady() {
+    }
+
+    public void systemReady2() {
+        // Start the status bar app
+        Intent intent = new Intent(ACTION_STATUSBAR_START);
+        mContext.sendBroadcast(intent /** permission  **/);
+    }
+
+    // ================================================================================
+    // From IStatusBarService
+    // ================================================================================
+    public void expand() {
+        enforceExpandStatusBar();
+
+        if (mBar != null) {
+            try {
+                mBar.animateExpand();
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
+    public void collapse() {
+        enforceExpandStatusBar();
+
+        if (mBar != null) {
+            try {
+                mBar.animateCollapse();
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
+    public void disable(int what, IBinder token, String pkg) {
+        enforceStatusBar();
+
+        // It's important that the the callback and the call to mBar get done
+        // in the same order when multiple threads are calling this function
+        // so they are paired correctly.  The messages on the handler will be
+        // handled in the order they were enqueued, but will be outside the lock.
+        synchronized (mDisableRecords) {
+            manageDisableListLocked(what, token, pkg);
+            final int net = gatherDisableActionsLocked();
+            Slog.d(TAG, "disable... net=0x" + Integer.toHexString(net));
+            if (net != mDisabled) {
+                mDisabled = net;
+                mHandler.post(new Runnable() {
+                        public void run() {
+                            mNotificationCallbacks.onSetDisabled(net);
+                        }
+                    });
+                if (mBar != null) {
+                    try {
+                        mBar.disable(net);
+                    } catch (RemoteException ex) {
+                    }
+                }
+            }
+        }
+    }
+
+    public void setIcon(String slot, String iconPackage, int iconId, int iconLevel) {
+        enforceStatusBar();
+
+        synchronized (mIcons) {
+            int index = mIcons.getSlotIndex(slot);
+            if (index < 0) {
+                throw new SecurityException("invalid status bar icon slot: " + slot);
+            }
+
+            StatusBarIcon icon = new StatusBarIcon(iconPackage, iconId, iconLevel);
+            //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon);
+            mIcons.setIcon(index, icon);
+
+            if (mBar != null) {
+                try {
+                    mBar.setIcon(index, icon);
+                } catch (RemoteException ex) {
+                }
+            }
+        }
+    }
+
+    public void setIconVisibility(String slot, boolean visible) {
+        enforceStatusBar();
+
+        synchronized (mIcons) {
+            int index = mIcons.getSlotIndex(slot);
+            if (index < 0) {
+                throw new SecurityException("invalid status bar icon slot: " + slot);
+            }
+
+            StatusBarIcon icon = mIcons.getIcon(index);
+            if (icon == null) {
+                return;
+            }
+
+            if (icon.visible != visible) {
+                icon.visible = visible;
+
+                if (mBar != null) {
+                    try {
+                        mBar.setIcon(index, icon);
+                    } catch (RemoteException ex) {
+                    }
+                }
+            }
+        }
+    }
+
+    public void removeIcon(String slot) {
+        enforceStatusBar();
+
+        synchronized (mIcons) {
+            int index = mIcons.getSlotIndex(slot);
+            if (index < 0) {
+                throw new SecurityException("invalid status bar icon slot: " + slot);
+            }
+
+            mIcons.removeIcon(index);
+
+            if (mBar != null) {
+                try {
+                    mBar.removeIcon(index);
+                } catch (RemoteException ex) {
+                }
+            }
+        }
+    }
+
+    private void enforceStatusBar() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR,
+                "StatusBarManagerService");
+    }
+
+    private void enforceExpandStatusBar() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.EXPAND_STATUS_BAR,
+                "StatusBarManagerService");
+    }
+
+
+    // ================================================================================
+    // Callbacks from the status bar service.
+    // ================================================================================
+    public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,
+            List<IBinder> notificationKeys, List<StatusBarNotification> notifications) {
+        Slog.i(TAG, "registerStatusBar bar=" + bar);
+        mBar = bar;
+        synchronized (mIcons) {
+            iconList.copyFrom(mIcons);
+        }
+        synchronized (mNotifications) {
+            for (Map.Entry<IBinder,StatusBarNotification> e: mNotifications.entrySet()) {
+                notificationKeys.add(e.getKey());
+                notifications.add(e.getValue());
+            }
+        }
+    }
+
+    /**
+     * The status bar service should call this when the user changes whether
+     * the status bar is visible or not.
+     */
+    public void visibilityChanged(boolean visible) {
+        //Slog.d(TAG, "visibilityChanged visible=" + visible);
+    }
+
+    public void onNotificationClick(String pkg, String tag, int id) {
+        mNotificationCallbacks.onNotificationClick(pkg, tag, id);
+    }
+
+    public void onClearAllNotifications() {
+        mNotificationCallbacks.onClearAll();
+    }
+
+    // ================================================================================
+    // Callbacks for NotificationManagerService.
+    // ================================================================================
+    public IBinder addNotification(StatusBarNotification notification) {
+        synchronized (mNotifications) {
+            IBinder key = new Binder();
+            mNotifications.put(key, notification);
+            if (mBar != null) {
+                try {
+                    mBar.addNotification(key, notification);
+                } catch (RemoteException ex) {
+                }
+            }
+            return key;
+        }
+    }
+
+    public void updateNotification(IBinder key, StatusBarNotification notification) {
+        synchronized (mNotifications) {
+            if (!mNotifications.containsKey(key)) {
+                throw new IllegalArgumentException("updateNotification key not found: " + key);
+            }
+            mNotifications.put(key, notification);
+            if (mBar != null) {
+                try {
+                    mBar.updateNotification(key, notification);
+                } catch (RemoteException ex) {
+                }
+            }
+        }
+    }
+
+    public void removeNotification(IBinder key) {
+        synchronized (mNotifications) {
+            final StatusBarNotification n = mNotifications.remove(key);
+            if (n == null) {
+                throw new IllegalArgumentException("removeNotification key not found: " + key);
+            }
+            if (mBar != null) {
+                try {
+                    mBar.removeNotification(key);
+                } catch (RemoteException ex) {
+                }
+            }
+        }
+    }
+
+    // ================================================================================
+    // Can be called from any thread
+    // ================================================================================
+
+    // lock on mDisableRecords
+    void manageDisableListLocked(int what, IBinder token, String pkg) {
+        if (SPEW) {
+            Slog.d(TAG, "manageDisableList what=0x" + Integer.toHexString(what) + " pkg=" + pkg);
+        }
+        // update the list
+        synchronized (mDisableRecords) {
+            final int N = mDisableRecords.size();
+            DisableRecord tok = null;
+            int i;
+            for (i=0; i<N; i++) {
+                DisableRecord t = mDisableRecords.get(i);
+                if (t.token == token) {
+                    tok = t;
+                    break;
+                }
+            }
+            if (what == 0 || !token.isBinderAlive()) {
+                if (tok != null) {
+                    mDisableRecords.remove(i);
+                    tok.token.unlinkToDeath(tok, 0);
+                }
+            } else {
+                if (tok == null) {
+                    tok = new DisableRecord();
+                    try {
+                        token.linkToDeath(tok, 0);
+                    }
+                    catch (RemoteException ex) {
+                        return; // give up
+                    }
+                    mDisableRecords.add(tok);
+                }
+                tok.what = what;
+                tok.token = token;
+                tok.pkg = pkg;
+            }
+        }
+    }
+
+    // lock on mDisableRecords
+    int gatherDisableActionsLocked() {
+        final int N = mDisableRecords.size();
+        // gather the new net flags
+        int net = 0;
+        for (int i=0; i<N; i++) {
+            net |= mDisableRecords.get(i).what;
+        }
+        return net;
+    }
+
+    // ================================================================================
+    // Always called from UI thread
+    // ================================================================================
+
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump StatusBar from from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid());
+            return;
+        }
+
+        synchronized (mIcons) {
+            mIcons.dump(pw);
+        }
+
+        synchronized (mNotifications) {
+            int i=0;
+            pw.println("Notification list:");
+            for (Map.Entry<IBinder,StatusBarNotification> e: mNotifications.entrySet()) {
+                pw.printf("  %2d: %s\n", i, e.getValue().toString());
+                i++;
+            }
+        }
+
+        synchronized (mDisableRecords) {
+            final int N = mDisableRecords.size();
+            pw.println("  mDisableRecords.size=" + N
+                    + " mDisabled=0x" + Integer.toHexString(mDisabled));
+            for (int i=0; i<N; i++) {
+                DisableRecord tok = mDisableRecords.get(i);
+                pw.println("    [" + i + "] what=0x" + Integer.toHexString(tok.what)
+                                + " pkg=" + tok.pkg + " token=" + tok.token);
+            }
+        }
+    }
+
+    /**
+     * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
+     * This was added last-minute and is inconsistent with the way the rest of the notifications
+     * are handled, because the notification isn't really cancelled.  The lights are just
+     * turned off.  If any other notifications happen, the lights will turn back on.  Steve says
+     * this is what he wants. (see bug 1131461)
+     */
+    private boolean mPanelSlightlyVisible;
+    void panelSlightlyVisible(boolean visible) {
+        if (mPanelSlightlyVisible != visible) {
+            mPanelSlightlyVisible = visible;
+            if (visible) {
+                // tell the notification manager to turn off the lights.
+                mNotificationCallbacks.onPanelRevealed();
+            }
+        }
+    }
+
+    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
+                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
+                collapse();
+            }
+            /*
+            else if (Telephony.Intents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
+                updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false),
+                        intent.getStringExtra(Telephony.Intents.EXTRA_SPN),
+                        intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false),
+                        intent.getStringExtra(Telephony.Intents.EXTRA_PLMN));
+            }
+            else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+                updateResources();
+            }
+            */
+        }
+    };
+
+}
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
deleted file mode 100644
index cab2662..0000000
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ /dev/null
@@ -1,1411 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.status;
-
-import android.app.AlertDialog;
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothPbap;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.TypedArray;
-import android.graphics.PixelFormat;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.location.LocationManager;
-import android.media.AudioManager;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.net.NetworkInfo;
-import android.net.Uri;
-import android.net.wifi.WifiManager;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.storage.StorageManager;
-import android.provider.Settings;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.TelephonyManager;
-import android.text.format.DateFormat;
-import android.text.style.CharacterStyle;
-import android.text.style.RelativeSizeSpan;
-import android.text.style.ForegroundColorSpan;
-import android.text.style.StyleSpan;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
-import android.util.Slog;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.WindowManagerImpl;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.internal.R;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.cdma.EriInfo;
-import com.android.internal.telephony.cdma.TtyIntent;
-import com.android.server.am.BatteryStatsService;
-
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.TimeZone;
-
-/**
- * This class contains all of the policy about which icons are installed in the status
- * bar at boot time.  In reality, it should go into the android.policy package, but
- * putting it here is the first step from extracting it.
- */
-public class StatusBarPolicy {
-    private static final String TAG = "StatusBarPolicy";
-
-    private static StatusBarPolicy sInstance;
-
-    // message codes for the handler
-    private static final int EVENT_BATTERY_CLOSE = 4;
-
-    private static final int AM_PM_STYLE_NORMAL  = 0;
-    private static final int AM_PM_STYLE_SMALL   = 1;
-    private static final int AM_PM_STYLE_GONE    = 2;
-
-    private static final int AM_PM_STYLE = AM_PM_STYLE_GONE;
-
-    private final Context mContext;
-    private final StatusBarService mService;
-    private final Handler mHandler = new StatusBarHandler();
-    private final IBatteryStats mBatteryStats;
-
-    // clock
-    private Calendar mCalendar;
-    private String mClockFormatString;
-    private SimpleDateFormat mClockFormat;
-    private IBinder mClockIcon;
-    private IconData mClockData;
-
-    // storage
-    private StorageManager mStorageManager;
-
-    // battery
-    private IBinder mBatteryIcon;
-    private IconData mBatteryData;
-    private boolean mBatteryFirst = true;
-    private boolean mBatteryPlugged;
-    private int mBatteryLevel;
-    private AlertDialog mLowBatteryDialog;
-    private TextView mBatteryLevelTextView;
-    private View mBatteryView;
-    private int mBatteryViewSequence;
-    private boolean mBatteryShowLowOnEndCall = false;
-    private static final boolean SHOW_LOW_BATTERY_WARNING = true;
-    private static final boolean SHOW_BATTERY_WARNINGS_IN_CALL = true;
-
-    // phone
-    private TelephonyManager mPhone;
-    private IBinder mPhoneIcon;
-
-    //***** Signal strength icons
-    private IconData mPhoneData;
-    //GSM/UMTS
-    private static final int[] sSignalImages = new int[] {
-        com.android.internal.R.drawable.stat_sys_signal_0,
-        com.android.internal.R.drawable.stat_sys_signal_1,
-        com.android.internal.R.drawable.stat_sys_signal_2,
-        com.android.internal.R.drawable.stat_sys_signal_3,
-        com.android.internal.R.drawable.stat_sys_signal_4
-    };
-    private static final int[] sSignalImages_r = new int[] {
-        com.android.internal.R.drawable.stat_sys_r_signal_0,
-        com.android.internal.R.drawable.stat_sys_r_signal_1,
-        com.android.internal.R.drawable.stat_sys_r_signal_2,
-        com.android.internal.R.drawable.stat_sys_r_signal_3,
-        com.android.internal.R.drawable.stat_sys_r_signal_4
-    };
-    private static final int[] sRoamingIndicatorImages_cdma = new int[] {
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator
-        // 1 is Standard Roaming Indicator OFF
-        // TODO T: image never used, remove and put 0 instead?
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-
-        // 2 is Standard Roaming Indicator FLASHING
-        // TODO T: image never used, remove and put 0 instead?
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-
-        // 3-12 Standard ERI
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //3
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-
-        // 13-63 Reserved for Standard ERI
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //13
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-
-        // 64-127 Reserved for Non Standard (Operator Specific) ERI
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //64
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
-        com.android.internal.R.drawable.stat_sys_roaming_cdma_0 //83
-
-        // 128-255 Reserved
-    };
-
-    //***** Data connection icons
-    private int[] mDataIconList = sDataNetType_g;
-    //GSM/UMTS
-    private static final int[] sDataNetType_g = new int[] {
-            com.android.internal.R.drawable.stat_sys_data_connected_g,
-            com.android.internal.R.drawable.stat_sys_data_in_g,
-            com.android.internal.R.drawable.stat_sys_data_out_g,
-            com.android.internal.R.drawable.stat_sys_data_inandout_g,
-        };
-    private static final int[] sDataNetType_3g = new int[] {
-            com.android.internal.R.drawable.stat_sys_data_connected_3g,
-            com.android.internal.R.drawable.stat_sys_data_in_3g,
-            com.android.internal.R.drawable.stat_sys_data_out_3g,
-            com.android.internal.R.drawable.stat_sys_data_inandout_3g,
-        };
-    private static final int[] sDataNetType_e = new int[] {
-            com.android.internal.R.drawable.stat_sys_data_connected_e,
-            com.android.internal.R.drawable.stat_sys_data_in_e,
-            com.android.internal.R.drawable.stat_sys_data_out_e,
-            com.android.internal.R.drawable.stat_sys_data_inandout_e,
-        };
-    //3.5G
-    private static final int[] sDataNetType_h = new int[] {
-            com.android.internal.R.drawable.stat_sys_data_connected_h,
-            com.android.internal.R.drawable.stat_sys_data_in_h,
-            com.android.internal.R.drawable.stat_sys_data_out_h,
-            com.android.internal.R.drawable.stat_sys_data_inandout_h,
-    };
-
-    //CDMA
-    // Use 3G icons for EVDO data and 1x icons for 1XRTT data
-    private static final int[] sDataNetType_1x = new int[] {
-        com.android.internal.R.drawable.stat_sys_data_connected_1x,
-        com.android.internal.R.drawable.stat_sys_data_in_1x,
-        com.android.internal.R.drawable.stat_sys_data_out_1x,
-        com.android.internal.R.drawable.stat_sys_data_inandout_1x,
-    };
-
-    // Assume it's all good unless we hear otherwise.  We don't always seem
-    // to get broadcasts that it *is* there.
-    IccCard.State mSimState = IccCard.State.READY;
-    int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
-    int mDataState = TelephonyManager.DATA_DISCONNECTED;
-    int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
-    ServiceState mServiceState;
-    SignalStrength mSignalStrength;
-
-    // data connection
-    private IBinder mDataIcon;
-    private IconData mDataData;
-    private boolean mDataIconVisible;
-    private boolean mHspaDataDistinguishable;
-
-    // ringer volume
-    private IBinder mVolumeIcon;
-    private IconData mVolumeData;
-    private boolean mVolumeVisible;
-
-    // bluetooth device status
-    private IBinder mBluetoothIcon;
-    private IconData mBluetoothData;
-    private int mBluetoothHeadsetState;
-    private boolean mBluetoothA2dpConnected;
-    private int mBluetoothPbapState;
-    private boolean mBluetoothEnabled;
-
-    // wifi
-    private static final int[] sWifiSignalImages = new int[] {
-            com.android.internal.R.drawable.stat_sys_wifi_signal_1,
-            com.android.internal.R.drawable.stat_sys_wifi_signal_2,
-            com.android.internal.R.drawable.stat_sys_wifi_signal_3,
-            com.android.internal.R.drawable.stat_sys_wifi_signal_4,
-        };
-    private static final int sWifiTemporarilyNotConnectedImage =
-            com.android.internal.R.drawable.stat_sys_wifi_signal_0;
-
-    private int mLastWifiSignalLevel = -1;
-    private boolean mIsWifiConnected = false;
-    private IBinder mWifiIcon;
-    private IconData mWifiData;
-
-    // gps
-    private IBinder mGpsIcon;
-    private IconData mGpsEnabledIconData;
-    private IconData mGpsFixIconData;
-
-    // alarm clock
-    // Icon lit when clock is set
-    private IBinder mAlarmClockIcon;
-    private IconData mAlarmClockIconData;
-
-    // sync state
-    // If sync is active the SyncActive icon is displayed. If sync is not active but
-    // sync is failing the SyncFailing icon is displayed. Otherwise neither are displayed.
-    private IBinder mSyncActiveIcon;
-    private IBinder mSyncFailingIcon;
-
-    // TTY mode
-    // Icon lit when TTY mode is enabled
-    private IBinder mTTYModeIcon;
-    private IconData mTTYModeEnableIconData;
-
-    // Cdma Roaming Indicator, ERI
-    private IBinder mCdmaRoamingIndicatorIcon;
-    private IconData mCdmaRoamingIndicatorIconData;
-
-    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(Intent.ACTION_TIME_TICK)) {
-                updateClock();
-            }
-            else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
-                updateClock();
-            }
-            else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
-                updateBattery(intent);
-            }
-            else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
-                updateClock();
-            }
-            else if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
-                String tz = intent.getStringExtra("time-zone");
-                mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
-                if (mClockFormat != null) {
-                    mClockFormat.setTimeZone(mCalendar.getTimeZone());
-                }
-                updateClock();
-            }
-            else if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
-                updateAlarm(intent);
-            }
-            else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
-                updateSyncState(intent);
-            }
-            else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
-                onBatteryLow(intent);
-            }
-            else if (action.equals(Intent.ACTION_BATTERY_OKAY)
-                    || action.equals(Intent.ACTION_POWER_CONNECTED)) {
-                onBatteryOkay(intent);
-            }
-            else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED) ||
-                    action.equals(BluetoothHeadset.ACTION_STATE_CHANGED) ||
-                    action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED) ||
-                    action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
-                updateBluetooth(intent);
-            }
-            else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) ||
-                    action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) ||
-                    action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
-                updateWifi(intent);
-            }
-            else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) ||
-                    action.equals(LocationManager.GPS_FIX_CHANGE_ACTION)) {
-                updateGps(intent);
-            }
-            else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) ||
-                    action.equals(AudioManager.VIBRATE_SETTING_CHANGED_ACTION)) {
-                updateVolume();
-            }
-            else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
-                updateSimState(intent);
-            }
-            else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
-                updateTTY(intent);
-            }
-        }
-    };
-
-    private StatusBarPolicy(Context context, StatusBarService service) {
-        mContext = context;
-        mService = service;
-        mSignalStrength = new SignalStrength();
-        mBatteryStats = BatteryStatsService.getService();
-
-        // clock
-        mCalendar = Calendar.getInstance(TimeZone.getDefault());
-        mClockData = IconData.makeText("clock", "");
-        mClockIcon = service.addIcon(mClockData, null);
-        updateClock();
-
-        // storage
-        mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
-        mStorageManager.registerListener(
-                new com.android.server.status.StorageNotification(context));
-
-        // battery
-        mBatteryData = IconData.makeIcon("battery",
-                null, com.android.internal.R.drawable.stat_sys_battery_unknown, 0, 0);
-        mBatteryIcon = service.addIcon(mBatteryData, null);
-
-        // phone_signal
-        mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
-        mPhoneData = IconData.makeIcon("phone_signal",
-                null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0);
-        mPhoneIcon = service.addIcon(mPhoneData, null);
-
-        // register for phone state notifications.
-        ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
-                .listen(mPhoneStateListener,
-                          PhoneStateListener.LISTEN_SERVICE_STATE
-                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
-                        | PhoneStateListener.LISTEN_CALL_STATE
-                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
-                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
-
-        // data_connection
-        mDataData = IconData.makeIcon("data_connection",
-                null, com.android.internal.R.drawable.stat_sys_data_connected_g, 0, 0);
-        mDataIcon = service.addIcon(mDataData, null);
-        service.setIconVisibility(mDataIcon, false);
-
-        // wifi
-        mWifiData = IconData.makeIcon("wifi", null, sWifiSignalImages[0], 0, 0);
-        mWifiIcon = service.addIcon(mWifiData, null);
-        service.setIconVisibility(mWifiIcon, false);
-        // wifi will get updated by the sticky intents
-
-        // TTY status
-        mTTYModeEnableIconData = IconData.makeIcon("tty",
-                null, com.android.internal.R.drawable.stat_sys_tty_mode, 0, 0);
-        mTTYModeIcon = service.addIcon(mTTYModeEnableIconData, null);
-        service.setIconVisibility(mTTYModeIcon, false);
-
-        // Cdma Roaming Indicator, ERI
-        mCdmaRoamingIndicatorIconData = IconData.makeIcon("cdma_eri",
-                null, com.android.internal.R.drawable.stat_sys_roaming_cdma_0, 0, 0);
-        mCdmaRoamingIndicatorIcon = service.addIcon(mCdmaRoamingIndicatorIconData, null);
-        service.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
-
-        // bluetooth status
-        mBluetoothData = IconData.makeIcon("bluetooth",
-                null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0);
-        mBluetoothIcon = service.addIcon(mBluetoothData, null);
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        if (adapter != null) {
-            mBluetoothEnabled = adapter.isEnabled();
-        } else {
-            mBluetoothEnabled = false;
-        }
-        mBluetoothA2dpConnected = false;
-        mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED;
-        mBluetoothPbapState = BluetoothPbap.STATE_DISCONNECTED;
-        mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
-
-        // Gps status
-        mGpsEnabledIconData = IconData.makeIcon("gps",
-                null, com.android.internal.R.drawable.stat_sys_gps_acquiring_anim, 0, 0);
-        mGpsFixIconData = IconData.makeIcon("gps",
-                null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0);
-        mGpsIcon = service.addIcon(mGpsEnabledIconData, null);
-        service.setIconVisibility(mGpsIcon, false);
-
-        // Alarm clock
-        mAlarmClockIconData = IconData.makeIcon(
-                "alarm_clock",
-                null, com.android.internal.R.drawable.stat_notify_alarm, 0, 0);
-        mAlarmClockIcon = service.addIcon(mAlarmClockIconData, null);
-        service.setIconVisibility(mAlarmClockIcon, false);
-
-        // Sync state
-        mSyncActiveIcon = service.addIcon(IconData.makeIcon("sync_active",
-                null, R.drawable.stat_notify_sync_anim0, 0, 0), null);
-        mSyncFailingIcon = service.addIcon(IconData.makeIcon("sync_failing",
-                null, R.drawable.stat_notify_sync_error, 0, 0), null);
-        service.setIconVisibility(mSyncActiveIcon, false);
-        service.setIconVisibility(mSyncFailingIcon, false);
-
-        // volume
-        mVolumeData = IconData.makeIcon("volume",
-                null, com.android.internal.R.drawable.stat_sys_ringer_silent, 0, 0);
-        mVolumeIcon = service.addIcon(mVolumeData, null);
-        service.setIconVisibility(mVolumeIcon, false);
-        updateVolume();
-
-        IntentFilter filter = new IntentFilter();
-
-        // Register for Intent broadcasts for...
-        filter.addAction(Intent.ACTION_TIME_TICK);
-        filter.addAction(Intent.ACTION_TIME_CHANGED);
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
-        filter.addAction(Intent.ACTION_BATTERY_LOW);
-        filter.addAction(Intent.ACTION_BATTERY_OKAY);
-        filter.addAction(Intent.ACTION_POWER_CONNECTED);
-        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
-        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(BluetoothHeadset.ACTION_STATE_CHANGED);
-        filter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
-        filter.addAction(BluetoothPbap.PBAP_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
-        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
-        filter.addAction(LocationManager.GPS_ENABLED_CHANGE_ACTION);
-        filter.addAction(LocationManager.GPS_FIX_CHANGE_ACTION);
-        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
-        filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
-        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
-
-        // load config to determine if to distinguish Hspa data icon
-        try {
-            mHspaDataDistinguishable = mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_hspa_data_distinguishable);
-        } catch (Exception e) {
-            mHspaDataDistinguishable = false;
-        }
-    }
-
-    public static void installIcons(Context context, StatusBarService service) {
-        sInstance = new StatusBarPolicy(context, service);
-    }
-
-    private final CharSequence getSmallTime() {
-        boolean b24 = DateFormat.is24HourFormat(mContext);
-        int res;
-
-        if (b24) {
-            res = R.string.twenty_four_hour_time_format;
-        } else {
-            res = R.string.twelve_hour_time_format;
-        }
-
-        final char MAGIC1 = '\uEF00';
-        final char MAGIC2 = '\uEF01';
-
-        SimpleDateFormat sdf;
-        String format = mContext.getString(res);
-        if (!format.equals(mClockFormatString)) {
-            /*
-             * Search for an unquoted "a" in the format string, so we can
-             * add dummy characters around it to let us find it again after
-             * formatting and change its size.
-             */
-            if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) {
-                int a = -1;
-                boolean quoted = false;
-                for (int i = 0; i < format.length(); i++) {
-                    char c = format.charAt(i);
-
-                    if (c == '\'') {
-                        quoted = !quoted;
-                    }
-
-                    if (!quoted && c == 'a') {
-                        a = i;
-                        break;
-                    }
-                }
-
-                if (a >= 0) {
-                    // Move a back so any whitespace before the AM/PM is also in the alternate size.
-                    final int b = a;
-                    while (a > 0 && Character.isWhitespace(format.charAt(a-1))) {
-                        a--;
-                    }
-                    format = format.substring(0, a) + MAGIC1 + format.substring(a, b)
-                            + "a" + MAGIC2 + format.substring(b + 1);
-                }
-            }
-
-            mClockFormat = sdf = new SimpleDateFormat(format);
-            mClockFormatString = format;
-        } else {
-            sdf = mClockFormat;
-        }
-        String result = sdf.format(mCalendar.getTime());
-
-        if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) {
-            int magic1 = result.indexOf(MAGIC1);
-            int magic2 = result.indexOf(MAGIC2);
-
-            if (magic1 >= 0 && magic2 > magic1) {
-                SpannableStringBuilder formatted = new SpannableStringBuilder(result);
-
-                if (AM_PM_STYLE == AM_PM_STYLE_GONE) {
-                    formatted.delete(magic1, magic2+1);
-                } else {
-                    if (AM_PM_STYLE == AM_PM_STYLE_SMALL) {
-                        CharacterStyle style = new RelativeSizeSpan(0.7f);
-                        formatted.setSpan(style, magic1, magic2,
-                                          Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
-                    }
-
-                    formatted.delete(magic2, magic2 + 1);
-                    formatted.delete(magic1, magic1 + 1);
-                }
-
-                return formatted;
-            }
-        }
- 
-        return result;
-    }
-
-    private final void updateClock() {
-        mCalendar.setTimeInMillis(System.currentTimeMillis());
-        mClockData.text = getSmallTime();
-        mService.updateIcon(mClockIcon, mClockData, null);
-    }
-
-    private final void updateAlarm(Intent intent) {
-        boolean alarmSet = intent.getBooleanExtra("alarmSet", false);
-        mService.setIconVisibility(mAlarmClockIcon, alarmSet);
-    }
-
-    private final void updateSyncState(Intent intent) {
-        boolean isActive = intent.getBooleanExtra("active", false);
-        boolean isFailing = intent.getBooleanExtra("failing", false);
-        mService.setIconVisibility(mSyncActiveIcon, isActive);
-        // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never"
-        //mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive);
-    }
-
-    private final void updateBattery(Intent intent) {
-        mBatteryData.iconId = intent.getIntExtra("icon-small", 0);
-        mBatteryData.iconLevel = intent.getIntExtra("level", 0);
-        mService.updateIcon(mBatteryIcon, mBatteryData, null);
-
-        boolean plugged = intent.getIntExtra("plugged", 0) != 0;
-        int level = intent.getIntExtra("level", -1);
-        if (false) {
-            Slog.d(TAG, "updateBattery level=" + level
-                    + " plugged=" + plugged
-                    + " mBatteryPlugged=" + mBatteryPlugged
-                    + " mBatteryLevel=" + mBatteryLevel
-                    + " mBatteryFirst=" + mBatteryFirst);
-        }
-
-        boolean oldPlugged = mBatteryPlugged;
-
-        mBatteryPlugged = plugged;
-        mBatteryLevel = level;
-
-        if (mBatteryFirst) {
-            mBatteryFirst = false;
-        }
-        /*
-         * No longer showing the battery view because it draws attention away
-         * from the USB storage notification. We could still show it when
-         * connected to a brick, but that could lead to the user into thinking
-         * the device does not charge when plugged into USB (since he/she would
-         * not see the same battery screen on USB as he sees on brick).
-         */
-        /* else {
-            if (plugged && !oldPlugged) {
-                showBatteryView();
-            }
-        }
-        */
-        if (false) {
-            Slog.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
-        }
-    }
-
-    private void onBatteryLow(Intent intent) {
-        if (SHOW_LOW_BATTERY_WARNING) {
-            if (false) {
-                Slog.d(TAG, "mPhoneState=" + mPhoneState
-                      + " mLowBatteryDialog=" + mLowBatteryDialog
-                      + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
-            }
-
-            if (SHOW_BATTERY_WARNINGS_IN_CALL || mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
-                showLowBatteryWarning();
-            } else {
-                mBatteryShowLowOnEndCall = true;
-            }
-        }
-    }
-
-    private void onBatteryOkay(Intent intent) {
-        if (mLowBatteryDialog != null
-                && SHOW_LOW_BATTERY_WARNING) {
-            mLowBatteryDialog.dismiss();
-            mBatteryShowLowOnEndCall = false;
-        }
-    }
-
-    private void showBatteryView() {
-        closeLastBatteryView();
-        if (mLowBatteryDialog != null) {
-            mLowBatteryDialog.dismiss();
-        }
-
-        int level = mBatteryLevel;
-
-        View v = View.inflate(mContext, com.android.internal.R.layout.battery_status, null);
-        mBatteryView = v;
-        int pixelFormat = PixelFormat.TRANSLUCENT;
-        Drawable bg = v.getBackground();
-        if (bg != null) {
-            pixelFormat = bg.getOpacity();
-        }
-
-        int flags =  WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                | WindowManager.LayoutParams.FLAG_DIM_BEHIND;
-
-        if (!mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_sf_slowBlur)) {
-            flags |= WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
-        }
-
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.WRAP_CONTENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT,
-                WindowManager.LayoutParams.TYPE_TOAST,
-                flags, pixelFormat);
-
-        // Get the dim amount from the theme
-        TypedArray a = mContext.obtainStyledAttributes(
-                com.android.internal.R.styleable.Theme);
-        lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f);
-        a.recycle();
-
-        lp.setTitle("Battery");
-
-        TextView levelTextView = (TextView)v.findViewById(com.android.internal.R.id.level_percent);
-        levelTextView.setText(mContext.getString(
-                    com.android.internal.R.string.battery_status_text_percent_format, level));
-
-        setBatteryLevel(v, com.android.internal.R.id.spacer, 100-level, 0, 0);
-        setBatteryLevel(v, com.android.internal.R.id.level, level,
-                com.android.internal.R.drawable.battery_charge_fill, level);
-
-        WindowManagerImpl.getDefault().addView(v, lp);
-
-        scheduleCloseBatteryView();
-    }
-
-    private void setBatteryLevel(View parent, int id, int height, int background, int level) {
-        ImageView v = (ImageView)parent.findViewById(id);
-        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)v.getLayoutParams();
-        lp.weight = height;
-        if (background != 0) {
-            v.setBackgroundResource(background);
-            Drawable bkg = v.getBackground();
-            bkg.setLevel(level);
-        }
-    }
-
-    private void showLowBatteryWarning() {
-        closeLastBatteryView();
-
-        // Show exact battery level.
-        CharSequence levelText = mContext.getString(
-                    com.android.internal.R.string.battery_low_percent_format, mBatteryLevel);
-
-        if (mBatteryLevelTextView != null) {
-            mBatteryLevelTextView.setText(levelText);
-        } else {
-            View v = View.inflate(mContext, com.android.internal.R.layout.battery_low, null);
-            mBatteryLevelTextView=(TextView)v.findViewById(com.android.internal.R.id.level_percent);
-
-            mBatteryLevelTextView.setText(levelText);
-
-            AlertDialog.Builder b = new AlertDialog.Builder(mContext);
-                b.setCancelable(true);
-                b.setTitle(com.android.internal.R.string.battery_low_title);
-                b.setView(v);
-                b.setIcon(android.R.drawable.ic_dialog_alert);
-                b.setPositiveButton(android.R.string.ok, null);
-
-                final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                        | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
-                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
-                        | Intent.FLAG_ACTIVITY_NO_HISTORY);
-                if (intent.resolveActivity(mContext.getPackageManager()) != null) {
-                    b.setNegativeButton(com.android.internal.R.string.battery_low_why,
-                            new DialogInterface.OnClickListener() {
-                        public void onClick(DialogInterface dialog, int which) {
-                            mContext.startActivity(intent);
-                            if (mLowBatteryDialog != null) {
-                                mLowBatteryDialog.dismiss();
-                            }
-                        }
-                    });
-                }
-
-            AlertDialog d = b.create();
-            d.setOnDismissListener(mLowBatteryListener);
-            d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-            d.show();
-            mLowBatteryDialog = d;
-        }
-
-        final ContentResolver cr = mContext.getContentResolver();
-        if (Settings.System.getInt(cr,
-                Settings.System.POWER_SOUNDS_ENABLED, 1) == 1)
-        {
-            final String soundPath = Settings.System.getString(cr,
-                Settings.System.LOW_BATTERY_SOUND);
-            if (soundPath != null) {
-                final Uri soundUri = Uri.parse("file://" + soundPath);
-                if (soundUri != null) {
-                    final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
-                    if (sfx != null) {
-                        sfx.setStreamType(AudioManager.STREAM_SYSTEM);
-                        sfx.play();
-                    }
-                }
-            }
-        }
-    }
-
-    private final void updateCallState(int state) {
-        mPhoneState = state;
-        if (false) {
-            Slog.d(TAG, "mPhoneState=" + mPhoneState
-                    + " mLowBatteryDialog=" + mLowBatteryDialog
-                    + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
-        }
-        if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
-            if (mBatteryShowLowOnEndCall) {
-                if (!mBatteryPlugged) {
-                    showLowBatteryWarning();
-                }
-                mBatteryShowLowOnEndCall = false;
-            }
-        } else {
-            if (mLowBatteryDialog != null) {
-                mLowBatteryDialog.dismiss();
-                mBatteryShowLowOnEndCall = true;
-            }
-        }
-    }
-
-    private DialogInterface.OnDismissListener mLowBatteryListener
-            = new DialogInterface.OnDismissListener() {
-        public void onDismiss(DialogInterface dialog) {
-            mLowBatteryDialog = null;
-            mBatteryLevelTextView = null;
-        }
-    };
-
-    private void scheduleCloseBatteryView() {
-        Message m = mHandler.obtainMessage(EVENT_BATTERY_CLOSE);
-        m.arg1 = (++mBatteryViewSequence);
-        mHandler.sendMessageDelayed(m, 3000);
-    }
-
-    private void closeLastBatteryView() {
-        if (mBatteryView != null) {
-            //mBatteryView.debug();
-            WindowManagerImpl.getDefault().removeView(mBatteryView);
-            mBatteryView = null;
-        }
-    }
-
-    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
-            mSignalStrength = signalStrength;
-            updateSignalStrength();
-        }
-
-        @Override
-        public void onServiceStateChanged(ServiceState state) {
-            mServiceState = state;
-            updateSignalStrength();
-            updateCdmaRoamingIcon(state);
-            updateDataIcon();
-        }
-
-        @Override
-        public void onCallStateChanged(int state, String incomingNumber) {
-            updateCallState(state);
-            // In cdma, if a voice call is made, RSSI should switch to 1x.
-            if (isCdma()) {
-                updateSignalStrength();
-            }
-        }
-
-        @Override
-        public void onDataConnectionStateChanged(int state, int networkType) {
-            mDataState = state;
-            updateDataNetType(networkType);
-            updateDataIcon();
-        }
-
-        @Override
-        public void onDataActivity(int direction) {
-            mDataActivity = direction;
-            updateDataIcon();
-        }
-    };
-
-    private final void updateSimState(Intent intent) {
-        String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
-        if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
-            mSimState = IccCard.State.ABSENT;
-        }
-        else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
-            mSimState = IccCard.State.READY;
-        }
-        else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
-            final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
-            if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
-                mSimState = IccCard.State.PIN_REQUIRED;
-            }
-            else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
-                mSimState = IccCard.State.PUK_REQUIRED;
-            }
-            else {
-                mSimState = IccCard.State.NETWORK_LOCKED;
-            }
-        } else {
-            mSimState = IccCard.State.UNKNOWN;
-        }
-        updateDataIcon();
-    }
-
-    private boolean isCdma() {
-        return (mSignalStrength != null) && !mSignalStrength.isGsm();
-    }
-
-    private boolean isEvdo() {
-        return ( (mServiceState != null)
-                 && ((mServiceState.getRadioTechnology()
-                        == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
-                     || (mServiceState.getRadioTechnology()
-                        == ServiceState.RADIO_TECHNOLOGY_EVDO_A)
-                     || (mServiceState.getRadioTechnology()
-                        == ServiceState.RADIO_TECHNOLOGY_EVDO_B)));
-    }
-
-    private boolean hasService() {
-        if (mServiceState != null) {
-            switch (mServiceState.getState()) {
-                case ServiceState.STATE_OUT_OF_SERVICE:
-                case ServiceState.STATE_POWER_OFF:
-                    return false;
-                default:
-                    return true;
-            }
-        } else {
-            return false;
-        }
-    }
-
-    private final void updateSignalStrength() {
-        int iconLevel = -1;
-        int[] iconList;
-
-        // Display signal strength while in "emergency calls only" mode
-        if (!hasService() && !mServiceState.isEmergencyOnly()) {
-            //Slog.d(TAG, "updateSignalStrength: no service");
-            if (Settings.System.getInt(mContext.getContentResolver(),
-                    Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
-                mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_flightmode;
-            } else {
-                mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null;
-            }
-            mService.updateIcon(mPhoneIcon, mPhoneData, null);
-            return;
-        }
-
-        if (!isCdma()) {
-            int asu = mSignalStrength.getGsmSignalStrength();
-
-            // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
-            // asu = 0 (-113dB or less) is very weak
-            // signal, its better to show 0 bars to the user in such cases.
-            // asu = 99 is a special case, where the signal strength is unknown.
-            if (asu <= 2 || asu == 99) iconLevel = 0;
-            else if (asu >= 12) iconLevel = 4;
-            else if (asu >= 8)  iconLevel = 3;
-            else if (asu >= 5)  iconLevel = 2;
-            else iconLevel = 1;
-
-            // Though mPhone is a Manager, this call is not an IPC
-            if (mPhone.isNetworkRoaming()) {
-                iconList = sSignalImages_r;
-            } else {
-                iconList = sSignalImages;
-            }
-        } else {
-            iconList = this.sSignalImages;
-
-            // If 3G(EV) and 1x network are available than 3G should be
-            // displayed, displayed RSSI should be from the EV side.
-            // If a voice call is made then RSSI should switch to 1x.
-            if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
-                iconLevel = getEvdoLevel();
-                if (false) {
-                    Slog.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel());
-                }
-            } else {
-                iconLevel = getCdmaLevel();
-            }
-        }
-        mPhoneData.iconId = iconList[iconLevel];
-        mService.updateIcon(mPhoneIcon, mPhoneData, null);
-    }
-
-    private int getCdmaLevel() {
-        final int cdmaDbm = mSignalStrength.getCdmaDbm();
-        final int cdmaEcio = mSignalStrength.getCdmaEcio();
-        int levelDbm = 0;
-        int levelEcio = 0;
-
-        if (cdmaDbm >= -75) levelDbm = 4;
-        else if (cdmaDbm >= -85) levelDbm = 3;
-        else if (cdmaDbm >= -95) levelDbm = 2;
-        else if (cdmaDbm >= -100) levelDbm = 1;
-        else levelDbm = 0;
-
-        // Ec/Io are in dB*10
-        if (cdmaEcio >= -90) levelEcio = 4;
-        else if (cdmaEcio >= -110) levelEcio = 3;
-        else if (cdmaEcio >= -130) levelEcio = 2;
-        else if (cdmaEcio >= -150) levelEcio = 1;
-        else levelEcio = 0;
-
-        return (levelDbm < levelEcio) ? levelDbm : levelEcio;
-    }
-
-    private int getEvdoLevel() {
-        int evdoDbm = mSignalStrength.getEvdoDbm();
-        int evdoSnr = mSignalStrength.getEvdoSnr();
-        int levelEvdoDbm = 0;
-        int levelEvdoSnr = 0;
-
-        if (evdoDbm >= -65) levelEvdoDbm = 4;
-        else if (evdoDbm >= -75) levelEvdoDbm = 3;
-        else if (evdoDbm >= -90) levelEvdoDbm = 2;
-        else if (evdoDbm >= -105) levelEvdoDbm = 1;
-        else levelEvdoDbm = 0;
-
-        if (evdoSnr >= 7) levelEvdoSnr = 4;
-        else if (evdoSnr >= 5) levelEvdoSnr = 3;
-        else if (evdoSnr >= 3) levelEvdoSnr = 2;
-        else if (evdoSnr >= 1) levelEvdoSnr = 1;
-        else levelEvdoSnr = 0;
-
-        return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
-    }
-
-    private final void updateDataNetType(int net) {
-        switch (net) {
-        case TelephonyManager.NETWORK_TYPE_EDGE:
-            mDataIconList = sDataNetType_e;
-            break;
-        case TelephonyManager.NETWORK_TYPE_UMTS:
-            mDataIconList = sDataNetType_3g;
-            break;
-        case TelephonyManager.NETWORK_TYPE_HSDPA:
-        case TelephonyManager.NETWORK_TYPE_HSUPA:
-        case TelephonyManager.NETWORK_TYPE_HSPA:
-            if (mHspaDataDistinguishable) {
-                mDataIconList = sDataNetType_h;
-            } else {
-                mDataIconList = sDataNetType_3g;
-            }
-            break;
-        case TelephonyManager.NETWORK_TYPE_CDMA:
-            // display 1xRTT for IS95A/B
-            mDataIconList = this.sDataNetType_1x;
-            break;
-        case TelephonyManager.NETWORK_TYPE_1xRTT:
-            mDataIconList = this.sDataNetType_1x;
-            break;
-        case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
-        case TelephonyManager.NETWORK_TYPE_EVDO_A:
-        case TelephonyManager.NETWORK_TYPE_EVDO_B:
-            mDataIconList = sDataNetType_3g;
-            break;
-        default:
-            mDataIconList = sDataNetType_g;
-        break;
-        }
-    }
-
-    private final void updateDataIcon() {
-        int iconId;
-        boolean visible = true;
-
-        if (!isCdma()) {
-            // GSM case, we have to check also the sim state
-            if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
-                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
-                    switch (mDataActivity) {
-                        case TelephonyManager.DATA_ACTIVITY_IN:
-                            iconId = mDataIconList[1];
-                            break;
-                        case TelephonyManager.DATA_ACTIVITY_OUT:
-                            iconId = mDataIconList[2];
-                            break;
-                        case TelephonyManager.DATA_ACTIVITY_INOUT:
-                            iconId = mDataIconList[3];
-                            break;
-                        default:
-                            iconId = mDataIconList[0];
-                            break;
-                    }
-                    mDataData.iconId = iconId;
-                    mService.updateIcon(mDataIcon, mDataData, null);
-                } else {
-                    visible = false;
-                }
-            } else {
-                mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim;
-                mService.updateIcon(mDataIcon, mDataData, null);
-            }
-        } else {
-            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
-            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
-                switch (mDataActivity) {
-                    case TelephonyManager.DATA_ACTIVITY_IN:
-                        iconId = mDataIconList[1];
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_OUT:
-                        iconId = mDataIconList[2];
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_INOUT:
-                        iconId = mDataIconList[3];
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_DORMANT:
-                    default:
-                        iconId = mDataIconList[0];
-                        break;
-                }
-                mDataData.iconId = iconId;
-                mService.updateIcon(mDataIcon, mDataData, null);
-            } else {
-                visible = false;
-            }
-        }
-
-        long ident = Binder.clearCallingIdentity();
-        try {
-            mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
-        } catch (RemoteException e) {
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-
-        if (mDataIconVisible != visible) {
-            mService.setIconVisibility(mDataIcon, visible);
-            mDataIconVisible = visible;
-        }
-    }
-
-    private final void updateVolume() {
-        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        final int ringerMode = audioManager.getRingerMode();
-        final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
-                ringerMode == AudioManager.RINGER_MODE_VIBRATE;
-        final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)
-                ? com.android.internal.R.drawable.stat_sys_ringer_vibrate
-                : com.android.internal.R.drawable.stat_sys_ringer_silent;
-
-        if (visible) {
-            mVolumeData.iconId = iconId;
-            mService.updateIcon(mVolumeIcon, mVolumeData, null);
-        }
-        if (visible != mVolumeVisible) {
-            mService.setIconVisibility(mVolumeIcon, visible);
-            mVolumeVisible = visible;
-        }
-    }
-
-    private final void updateBluetooth(Intent intent) {
-        int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth;
-        String action = intent.getAction();
-        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
-            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
-            mBluetoothEnabled = state == BluetoothAdapter.STATE_ON;
-        } else if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) {
-            mBluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
-                    BluetoothHeadset.STATE_ERROR);
-        } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
-            BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
-            if (a2dp.getConnectedSinks().size() != 0) {
-                mBluetoothA2dpConnected = true;
-            } else {
-                mBluetoothA2dpConnected = false;
-            }
-        } else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
-            mBluetoothPbapState = intent.getIntExtra(BluetoothPbap.PBAP_STATE,
-                    BluetoothPbap.STATE_DISCONNECTED);
-        } else {
-            return;
-        }
-
-        if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED || mBluetoothA2dpConnected ||
-                mBluetoothPbapState == BluetoothPbap.STATE_CONNECTED) {
-            iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected;
-        }
-
-        mBluetoothData.iconId = iconId;
-        mService.updateIcon(mBluetoothIcon, mBluetoothData, null);
-        mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
-    }
-
-    private final void updateWifi(Intent intent) {
-        final String action = intent.getAction();
-        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-
-            final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
-                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
-
-            if (!enabled) {
-                // If disabled, hide the icon. (We show icon when connected.)
-                mService.setIconVisibility(mWifiIcon, false);
-            }
-
-        } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
-            final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED,
-                                                           false);
-            if (!enabled) {
-                mService.setIconVisibility(mWifiIcon, false);
-            }
-        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-
-            final NetworkInfo networkInfo = (NetworkInfo)
-                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
-
-            int iconId;
-            if (networkInfo != null && networkInfo.isConnected()) {
-                mIsWifiConnected = true;
-                if (mLastWifiSignalLevel == -1) {
-                    iconId = sWifiSignalImages[0];
-                } else {
-                    iconId = sWifiSignalImages[mLastWifiSignalLevel];
-                }
-
-                // Show the icon since wi-fi is connected
-                mService.setIconVisibility(mWifiIcon, true);
-
-            } else {
-                mLastWifiSignalLevel = -1;
-                mIsWifiConnected = false;
-                iconId = sWifiSignalImages[0];
-
-                // Hide the icon since we're not connected
-                mService.setIconVisibility(mWifiIcon, false);
-            }
-
-            mWifiData.iconId = iconId;
-            mService.updateIcon(mWifiIcon, mWifiData, null);
-        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
-            final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
-            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
-                                                                  sWifiSignalImages.length);
-            if (newSignalLevel != mLastWifiSignalLevel) {
-                mLastWifiSignalLevel = newSignalLevel;
-                if (mIsWifiConnected) {
-                    mWifiData.iconId = sWifiSignalImages[newSignalLevel];
-                } else {
-                    mWifiData.iconId = sWifiTemporarilyNotConnectedImage;
-                }
-                mService.updateIcon(mWifiIcon, mWifiData, null);
-            }
-        }
-    }
-
-    private final void updateGps(Intent intent) {
-        final String action = intent.getAction();
-        final boolean enabled = intent.getBooleanExtra(LocationManager.EXTRA_GPS_ENABLED, false);
-
-        if (action.equals(LocationManager.GPS_FIX_CHANGE_ACTION) && enabled) {
-            // GPS is getting fixes
-            mService.updateIcon(mGpsIcon, mGpsFixIconData, null);
-            mService.setIconVisibility(mGpsIcon, true);
-        } else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
-            // GPS is off
-            mService.setIconVisibility(mGpsIcon, false);
-        } else {
-            // GPS is on, but not receiving fixes
-            mService.updateIcon(mGpsIcon, mGpsEnabledIconData, null);
-            mService.setIconVisibility(mGpsIcon, true);
-        }
-    }
-
-    private final void updateTTY(Intent intent) {
-        final String action = intent.getAction();
-        final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
-
-        if (false) Slog.v(TAG, "updateTTY: enabled: " + enabled);
-
-        if (enabled) {
-            // TTY is on
-            if (false) Slog.v(TAG, "updateTTY: set TTY on");
-            mService.updateIcon(mTTYModeIcon, mTTYModeEnableIconData, null);
-            mService.setIconVisibility(mTTYModeIcon, true);
-        } else {
-            // TTY is off
-            if (false) Slog.v(TAG, "updateTTY: set TTY off");
-            mService.setIconVisibility(mTTYModeIcon, false);
-        }
-    }
-
-    private final void updateCdmaRoamingIcon(ServiceState state) {
-        if (!hasService()) {
-            mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
-            return;
-        }
-
-        if (!isCdma()) {
-            mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
-            return;
-        }
-
-        int[] iconList = sRoamingIndicatorImages_cdma;
-        int iconIndex = state.getCdmaEriIconIndex();
-        int iconMode = state.getCdmaEriIconMode();
-
-        if (iconIndex == -1) {
-            Slog.e(TAG, "getCdmaEriIconIndex returned null, skipping ERI icon update");
-            return;
-        }
-
-        if (iconMode == -1) {
-            Slog.e(TAG, "getCdmeEriIconMode returned null, skipping ERI icon update");
-            return;
-        }
-
-        if (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) {
-            if (false) Slog.v(TAG, "Cdma ROAMING_INDICATOR_OFF, removing ERI icon");
-            mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
-            return;
-        }
-
-        switch (iconMode) {
-            case EriInfo.ROAMING_ICON_MODE_NORMAL:
-                mCdmaRoamingIndicatorIconData.iconId = iconList[iconIndex];
-                mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
-                mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
-                break;
-            case EriInfo.ROAMING_ICON_MODE_FLASH:
-                mCdmaRoamingIndicatorIconData.iconId =
-                        com.android.internal.R.drawable.stat_sys_roaming_cdma_flash;
-                mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
-                mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
-                break;
-
-        }
-        mService.updateIcon(mPhoneIcon, mPhoneData, null);
-    }
-
-
-    private class StatusBarHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-            case EVENT_BATTERY_CLOSE:
-                if (msg.arg1 == mBatteryViewSequence) {
-                    closeLastBatteryView();
-                }
-                break;
-            }
-        }
-    }
-}
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
deleted file mode 100644
index 93c8d34..0000000
--- a/services/java/com/android/server/status/StatusBarService.java
+++ /dev/null
@@ -1,1881 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.status;
-
-import com.android.internal.R;
-import com.android.internal.util.CharSequences;
-
-import android.app.ActivityManagerNative;
-import android.app.Dialog;
-import android.app.IStatusBar;
-import android.app.PendingIntent;
-import android.app.StatusBarManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.provider.Telephony;
-import android.util.Slog;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.WindowManagerImpl;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.widget.LinearLayout;
-import android.widget.RemoteViews;
-import android.widget.ScrollView;
-import android.widget.TextView;
-import android.widget.FrameLayout;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Set;
-
-
-/**
- * The public (ok, semi-public) service for the status bar.
- * <p>
- * This interesting thing to note about this class is that most of the methods that
- * are called from other classes just post a message, and everything else is batched
- * and coalesced into a series of calls to methods that all start with "perform."
- * There are two reasons for this.  The first is that some of the methods (activate/deactivate)
- * are on IStatusBar, so they're called from the thread pool and they need to make their
- * way onto the UI thread.  The second is that the message queue is stopped while animations
- * are happening in order to make for smoother transitions.
- * <p>
- * Each icon is either an icon or an icon and a notification.  They're treated mostly
- * separately throughout the code, although they both use the same key, which is assigned
- * when they are created.
- */
-public class StatusBarService extends IStatusBar.Stub
-{
-    static final String TAG = "StatusBar";
-    static final boolean SPEW = false;
-
-    static final int EXPANDED_LEAVE_ALONE = -10000;
-    static final int EXPANDED_FULL_OPEN = -10001;
-
-    private static final int MSG_ANIMATE = 1000;
-    private static final int MSG_ANIMATE_REVEAL = 1001;
-
-    private static final int OP_ADD_ICON = 1;
-    private static final int OP_UPDATE_ICON = 2;
-    private static final int OP_REMOVE_ICON = 3;
-    private static final int OP_SET_VISIBLE = 4;
-    private static final int OP_EXPAND = 5;
-    private static final int OP_TOGGLE = 6;
-    private static final int OP_DISABLE = 7;
-    private class PendingOp {
-        IBinder key;
-        int code;
-        IconData iconData;
-        NotificationData notificationData;
-        boolean visible;
-        int integer;
-    }
-
-    private class DisableRecord implements IBinder.DeathRecipient {
-        String pkg;
-        int what;
-        IBinder token;
-
-        public void binderDied() {
-            Slog.i(TAG, "binder died for pkg=" + pkg);
-            disable(0, token, pkg);
-            token.unlinkToDeath(this, 0);
-        }
-    }
-
-    public interface NotificationCallbacks {
-        void onSetDisabled(int status);
-        void onClearAll();
-        void onNotificationClick(String pkg, String tag, int id);
-        void onPanelRevealed();
-    }
-
-    private class ExpandedDialog extends Dialog {
-        ExpandedDialog(Context context) {
-            super(context, com.android.internal.R.style.Theme_Light_NoTitleBar);
-        }
-
-        @Override
-        public boolean dispatchKeyEvent(KeyEvent event) {
-            boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
-            switch (event.getKeyCode()) {
-            case KeyEvent.KEYCODE_BACK:
-                if (!down) {
-                    StatusBarService.this.deactivate();
-                }
-                return true;
-            }
-            return super.dispatchKeyEvent(event);
-        }
-    }
-    
-    final Context mContext;
-    final Display mDisplay;
-    StatusBarView mStatusBarView;
-    int mPixelFormat;
-    H mHandler = new H();
-    Object mQueueLock = new Object();
-    ArrayList<PendingOp> mQueue = new ArrayList<PendingOp>();
-    NotificationCallbacks mNotificationCallbacks;
-    
-    // All accesses to mIconMap and mNotificationData are syncronized on those objects,
-    // but this is only so dump() can work correctly.  Modifying these outside of the UI
-    // thread will not work, there are places in the code that unlock and reaquire between
-    // reads and require them to not be modified.
-
-    // icons
-    HashMap<IBinder,StatusBarIcon> mIconMap = new HashMap<IBinder,StatusBarIcon>();
-    ArrayList<StatusBarIcon> mIconList = new ArrayList<StatusBarIcon>();
-    String[] mRightIconSlots;
-    StatusBarIcon[] mRightIcons;
-    LinearLayout mIcons;
-    IconMerger mNotificationIcons;
-    LinearLayout mStatusIcons;
-    StatusBarIcon mMoreIcon;
-    private UninstallReceiver mUninstallReceiver;
-
-    // expanded notifications
-    NotificationViewList mNotificationData = new NotificationViewList();
-    Dialog mExpandedDialog;
-    ExpandedView mExpandedView;
-    WindowManager.LayoutParams mExpandedParams;
-    ScrollView mScrollView;
-    View mNotificationLinearLayout;
-    TextView mOngoingTitle;
-    LinearLayout mOngoingItems;
-    TextView mLatestTitle;
-    LinearLayout mLatestItems;
-    TextView mNoNotificationsTitle;
-    TextView mSpnLabel;
-    TextView mPlmnLabel;
-    TextView mClearButton;
-    View mExpandedContents;
-    CloseDragHandle mCloseView;
-    int[] mPositionTmp = new int[2];
-    boolean mExpanded;
-    boolean mExpandedVisible;
-
-    // the date view
-    DateView mDateView;
-
-    // the tracker view
-    TrackingView mTrackingView;
-    WindowManager.LayoutParams mTrackingParams;
-    int mTrackingPosition; // the position of the top of the tracking view.
-
-    // ticker
-    private Ticker mTicker;
-    private View mTickerView;
-    private boolean mTicking;
-    
-    // Tracking finger for opening/closing.
-    int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
-    boolean mTracking;
-    VelocityTracker mVelocityTracker;
-    
-    static final int ANIM_FRAME_DURATION = (1000/60);
-    
-    boolean mAnimating;
-    long mCurAnimationTime;
-    float mDisplayHeight;
-    float mAnimY;
-    float mAnimVel;
-    float mAnimAccel;
-    long mAnimLastTime;
-    boolean mAnimatingReveal = false;
-    int mViewDelta;
-    int[] mAbsPos = new int[2];
-    
-    // for disabling the status bar
-    ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
-    int mDisabled = 0;
-
-    /**
-     * Construct the service, add the status bar view to the window manager
-     */
-    public StatusBarService(Context context) {
-        mContext = context;
-        mDisplay = ((WindowManager)context.getSystemService(
-                Context.WINDOW_SERVICE)).getDefaultDisplay();
-        makeStatusBarView(context);
-        mUninstallReceiver = new UninstallReceiver();
-    }
-
-    public void setNotificationCallbacks(NotificationCallbacks listener) {
-        mNotificationCallbacks = listener;
-    }
-
-    // ================================================================================
-    // Constructing the view
-    // ================================================================================
-    private void makeStatusBarView(Context context) {
-        Resources res = context.getResources();
-        mRightIconSlots = res.getStringArray(com.android.internal.R.array.status_bar_icon_order);
-        mRightIcons = new StatusBarIcon[mRightIconSlots.length];
-
-        ExpandedView expanded = (ExpandedView)View.inflate(context,
-                com.android.internal.R.layout.status_bar_expanded, null);
-        expanded.mService = this;
-        StatusBarView sb = (StatusBarView)View.inflate(context,
-                com.android.internal.R.layout.status_bar, null);
-        sb.mService = this;
-
-        // figure out which pixel-format to use for the status bar.
-        mPixelFormat = PixelFormat.TRANSLUCENT;
-        Drawable bg = sb.getBackground();
-        if (bg != null) {
-            mPixelFormat = bg.getOpacity();
-        }
-
-        mStatusBarView = sb;
-        mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons);
-        mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons);
-        mNotificationIcons.service = this;
-        mIcons = (LinearLayout)sb.findViewById(R.id.icons);
-        mTickerView = sb.findViewById(R.id.ticker);
-        mDateView = (DateView)sb.findViewById(R.id.date);
-
-        mExpandedDialog = new ExpandedDialog(context);
-        mExpandedView = expanded;
-        mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout);
-        mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
-        mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
-        mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
-        mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
-        mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
-        mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
-        mClearButton.setOnClickListener(mClearButtonListener);
-        mSpnLabel = (TextView)expanded.findViewById(R.id.spnLabel);
-        mPlmnLabel = (TextView)expanded.findViewById(R.id.plmnLabel);
-        mScrollView = (ScrollView)expanded.findViewById(R.id.scroll);
-        mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout);
-
-        mOngoingTitle.setVisibility(View.GONE);
-        mLatestTitle.setVisibility(View.GONE);
-        
-        mTicker = new MyTicker(context, sb);
-
-        TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText);
-        tickerView.mTicker = mTicker;
-
-        mTrackingView = (TrackingView)View.inflate(context,
-                com.android.internal.R.layout.status_bar_tracking, null);
-        mTrackingView.mService = this;
-        mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close);
-        mCloseView.mService = this;
-
-        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
-
-        // add the more icon for the notifications
-        IconData moreData = IconData.makeIcon(null, context.getPackageName(),
-                R.drawable.stat_notify_more, 0, 42);
-        mMoreIcon = new StatusBarIcon(context, moreData, mNotificationIcons);
-        mMoreIcon.view.setId(R.drawable.stat_notify_more);
-        mNotificationIcons.moreIcon = mMoreIcon;
-        mNotificationIcons.addView(mMoreIcon.view);
-
-        // set the inital view visibility
-        setAreThereNotifications();
-        mDateView.setVisibility(View.INVISIBLE);
-
-        // before we register for broadcasts
-        mPlmnLabel.setText(R.string.lockscreen_carrier_default);
-        mPlmnLabel.setVisibility(View.VISIBLE);
-        mSpnLabel.setText("");
-        mSpnLabel.setVisibility(View.GONE);
-
-        // receive broadcasts
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-        filter.addAction(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION);
-        context.registerReceiver(mBroadcastReceiver, filter);
-    }
-
-    public void systemReady() {
-        final StatusBarView view = mStatusBarView;
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                view.getContext().getResources().getDimensionPixelSize(
-                        com.android.internal.R.dimen.status_bar_height),
-                WindowManager.LayoutParams.TYPE_STATUS_BAR,
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
-                WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING,
-                mPixelFormat);
-        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        lp.setTitle("StatusBar");
-        lp.windowAnimations = R.style.Animation_StatusBar;
-
-        WindowManagerImpl.getDefault().addView(view, lp);
-    }
-    
-    // ================================================================================
-    // From IStatusBar
-    // ================================================================================
-    public void activate() {
-        enforceExpandStatusBar();
-        addPendingOp(OP_EXPAND, null, true);
-    }
-
-    public void deactivate() {
-        enforceExpandStatusBar();
-        addPendingOp(OP_EXPAND, null, false);
-    }
-
-    public void toggle() {
-        enforceExpandStatusBar();
-        addPendingOp(OP_TOGGLE, null, false);
-    }
-
-    public void disable(int what, IBinder token, String pkg) {
-        enforceStatusBar();
-        synchronized (mNotificationCallbacks) {
-            // This is a little gross, but I think it's safe as long as nobody else
-            // synchronizes on mNotificationCallbacks.  It's important that the the callback
-            // and the pending op get done in the correct order and not interleaved with
-            // other calls, otherwise they'll get out of sync.
-            int net;
-            synchronized (mDisableRecords) {
-                manageDisableListLocked(what, token, pkg);
-                net = gatherDisableActionsLocked();
-                mNotificationCallbacks.onSetDisabled(net);
-            }
-            addPendingOp(OP_DISABLE, net);
-        }
-    }
-
-    public IBinder addIcon(String slot, String iconPackage, int iconId, int iconLevel) {
-        enforceStatusBar();
-        return addIcon(IconData.makeIcon(slot, iconPackage, iconId, iconLevel, 0), null);
-    }
-
-    public void updateIcon(IBinder key,
-            String slot, String iconPackage, int iconId, int iconLevel) {
-        enforceStatusBar();
-        updateIcon(key, IconData.makeIcon(slot, iconPackage, iconId, iconLevel, 0), null);
-    }
-
-    public void removeIcon(IBinder key) {
-        enforceStatusBar();
-        addPendingOp(OP_REMOVE_ICON, key, null, null, -1);
-    }
-
-    private void enforceStatusBar() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.STATUS_BAR,
-                "StatusBarService");
-    }
-
-    private void enforceExpandStatusBar() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.EXPAND_STATUS_BAR,
-                "StatusBarService");
-    }
-
-    // ================================================================================
-    // Can be called from any thread
-    // ================================================================================
-    public IBinder addIcon(IconData data, NotificationData n) {
-        int slot;
-        // assert early-on if they using a slot that doesn't exist.
-        if (data != null && n == null) {
-            slot = getRightIconIndex(data.slot);
-            if (slot < 0) {
-                throw new SecurityException("invalid status bar icon slot: "
-                        + (data.slot != null ? "'" + data.slot + "'" : "null"));
-            }
-        } else {
-            slot = -1;
-        }
-        IBinder key = new Binder();
-        addPendingOp(OP_ADD_ICON, key, data, n, -1);
-        return key;
-    }
-
-    public void updateIcon(IBinder key, IconData data, NotificationData n) {
-        addPendingOp(OP_UPDATE_ICON, key, data, n, -1);
-    }
-
-    public void setIconVisibility(IBinder key, boolean visible) {
-        addPendingOp(OP_SET_VISIBLE, key, visible);
-    }
-
-    private void addPendingOp(int code, IBinder key, IconData data, NotificationData n, int i) {
-        synchronized (mQueueLock) {
-            PendingOp op = new PendingOp();
-            op.key = key;
-            op.code = code;
-            op.iconData = data == null ? null : data.clone();
-            op.notificationData = n;
-            op.integer = i;
-            mQueue.add(op);
-            if (mQueue.size() == 1) {
-                mHandler.sendEmptyMessage(2);
-            }
-        }
-    }
-
-    private void addPendingOp(int code, IBinder key, boolean visible) {
-        synchronized (mQueueLock) {
-            PendingOp op = new PendingOp();
-            op.key = key;
-            op.code = code;
-            op.visible = visible;
-            mQueue.add(op);
-            if (mQueue.size() == 1) {
-                mHandler.sendEmptyMessage(1);
-            }
-        }
-    }
-
-    private void addPendingOp(int code, int integer) {
-        synchronized (mQueueLock) {
-            PendingOp op = new PendingOp();
-            op.code = code;
-            op.integer = integer;
-            mQueue.add(op);
-            if (mQueue.size() == 1) {
-                mHandler.sendEmptyMessage(1);
-            }
-        }
-    }
-
-    // lock on mDisableRecords
-    void manageDisableListLocked(int what, IBinder token, String pkg) {
-        if (SPEW) {
-            Slog.d(TAG, "manageDisableList what=0x" + Integer.toHexString(what)
-                    + " pkg=" + pkg);
-        }
-        // update the list
-        synchronized (mDisableRecords) {
-            final int N = mDisableRecords.size();
-            DisableRecord tok = null;
-            int i;
-            for (i=0; i<N; i++) {
-                DisableRecord t = mDisableRecords.get(i);
-                if (t.token == token) {
-                    tok = t;
-                    break;
-                }
-            }
-            if (what == 0 || !token.isBinderAlive()) {
-                if (tok != null) {
-                    mDisableRecords.remove(i);
-                    tok.token.unlinkToDeath(tok, 0);
-                }
-            } else {
-                if (tok == null) {
-                    tok = new DisableRecord();
-                    try {
-                        token.linkToDeath(tok, 0);
-                    }
-                    catch (RemoteException ex) {
-                        return; // give up
-                    }
-                    mDisableRecords.add(tok);
-                }
-                tok.what = what;
-                tok.token = token;
-                tok.pkg = pkg;
-            }
-        }
-    }
-
-    // lock on mDisableRecords
-    int gatherDisableActionsLocked() {
-        final int N = mDisableRecords.size();
-        // gather the new net flags
-        int net = 0;
-        for (int i=0; i<N; i++) {
-            net |= mDisableRecords.get(i).what;
-        }
-        return net;
-    }
-
-    private int getRightIconIndex(String slot) {
-        final int N = mRightIconSlots.length;
-        for (int i=0; i<N; i++) {
-            if (mRightIconSlots[i].equals(slot)) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    // ================================================================================
-    // Always called from UI thread
-    // ================================================================================
-    /**
-     * All changes to the status bar and notifications funnel through here and are batched.
-     */
-    private class H extends Handler {
-        public void handleMessage(Message m) {
-            if (m.what == MSG_ANIMATE) {
-                doAnimation();
-                return;
-            }
-            if (m.what == MSG_ANIMATE_REVEAL) {
-                doRevealAnimation();
-                return;
-            }
-
-            ArrayList<PendingOp> queue;
-            synchronized (mQueueLock) {
-                queue = mQueue;
-                mQueue = new ArrayList<PendingOp>();
-            }
-
-            boolean wasExpanded = mExpanded;
-
-            // for each one in the queue, find all of the ones with the same key
-            // and collapse that down into a final op and/or call to setVisibility, etc
-            boolean expand = wasExpanded;
-            boolean doExpand = false;
-            boolean doDisable = false;
-            int disableWhat = 0;
-            int N = queue.size();
-            while (N > 0) {
-                PendingOp op = queue.get(0);
-                boolean doOp = false;
-                boolean visible = false;
-                boolean doVisibility = false;
-                if (op.code == OP_SET_VISIBLE) {
-                    doVisibility = true;
-                    visible = op.visible;
-                }
-                else if (op.code == OP_EXPAND) {
-                    doExpand = true;
-                    expand = op.visible;
-                }
-                else if (op.code == OP_TOGGLE) {
-                    doExpand = true;
-                    expand = !expand;
-                }
-                else {
-                    doOp = true;
-                }
-
-                if (alwaysHandle(op.code)) {
-                    // coalesce these
-                    for (int i=1; i<N; i++) {
-                        PendingOp o = queue.get(i);
-                        if (!alwaysHandle(o.code) && o.key == op.key) {
-                            if (o.code == OP_SET_VISIBLE) {
-                                visible = o.visible;
-                                doVisibility = true;
-                            }
-                            else if (o.code == OP_EXPAND) {
-                                expand = o.visible;
-                                doExpand = true;
-                            }
-                            else {
-                                op.code = o.code;
-                                op.iconData = o.iconData;
-                                op.notificationData = o.notificationData;
-                            }
-                            queue.remove(i);
-                            i--;
-                            N--;
-                        }
-                    }
-                }
-
-                queue.remove(0);
-                N--;
-
-                if (doOp) {
-                    switch (op.code) {
-                        case OP_ADD_ICON:
-                        case OP_UPDATE_ICON:
-                            performAddUpdateIcon(op.key, op.iconData, op.notificationData);
-                            break;
-                        case OP_REMOVE_ICON:
-                            performRemoveIcon(op.key);
-                            break;
-                        case OP_DISABLE:
-                            doDisable = true;
-                            disableWhat = op.integer;
-                            break;
-                    }
-                }
-                if (doVisibility && op.code != OP_REMOVE_ICON) {
-                    performSetIconVisibility(op.key, visible);
-                }
-            }
-
-            if (queue.size() != 0) {
-                throw new RuntimeException("Assertion failed: queue.size=" + queue.size());
-            }
-            if (doExpand) {
-                // this is last so that we capture all of the pending changes before doing it
-                if (expand) {
-                    animateExpand();
-                } else {
-                    animateCollapse();
-                }
-            }
-            if (doDisable) {
-                performDisableActions(disableWhat);
-            }
-        }
-    }
-
-    private boolean alwaysHandle(int code) {
-        return code == OP_DISABLE;
-    }
-
-    /* private */ void performAddUpdateIcon(IBinder key, IconData data, NotificationData n)
-                        throws StatusBarException {
-        if (SPEW) {
-            Slog.d(TAG, "performAddUpdateIcon icon=" + data + " notification=" + n + " key=" + key);
-        }
-        // notification
-        if (n != null) {
-            StatusBarNotification notification = getNotification(key);
-            NotificationData oldData = null;
-            if (notification == null) {
-                // add
-                notification = new StatusBarNotification();
-                notification.key = key;
-                notification.data = n;
-                synchronized (mNotificationData) {
-                    mNotificationData.add(notification);
-                }
-                addNotificationView(notification);
-                setAreThereNotifications();
-            } else {
-                // update
-                oldData = notification.data;
-                notification.data = n;
-                updateNotificationView(notification, oldData);
-            }
-            // Show the ticker if one is requested, and the text is different
-            // than the currently displayed ticker.  Also don't do this
-            // until status bar window is attached to the window manager,
-            // because...  well, what's the point otherwise?  And trying to
-            // run a ticker without being attached will crash!
-            if (n.tickerText != null && mStatusBarView.getWindowToken() != null
-                    && (oldData == null
-                        || oldData.tickerText == null
-                        || !CharSequences.equals(oldData.tickerText, n.tickerText))) {
-                if (0 == (mDisabled & 
-                    (StatusBarManager.DISABLE_NOTIFICATION_ICONS | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
-                    mTicker.addEntry(n, StatusBarIcon.getIcon(mContext, data), n.tickerText);
-                }
-            }
-            updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-        }
-
-        // icon
-        synchronized (mIconMap) {
-            StatusBarIcon icon = mIconMap.get(key);
-            if (icon == null) {
-                // add
-                LinearLayout v = n == null ? mStatusIcons : mNotificationIcons;
-
-                icon = new StatusBarIcon(mContext, data, v);
-                mIconMap.put(key, icon);
-                mIconList.add(icon);
-
-                if (n == null) {
-                    int slotIndex = getRightIconIndex(data.slot);
-                    StatusBarIcon[] rightIcons = mRightIcons;
-                    if (rightIcons[slotIndex] == null) {
-                        int pos = 0;
-                        for (int i=mRightIcons.length-1; i>slotIndex; i--) {
-                            StatusBarIcon ic = rightIcons[i];
-                            if (ic != null) {
-                                pos++;
-                            }
-                        }
-                        rightIcons[slotIndex] = icon;
-                        mStatusIcons.addView(icon.view, pos);
-                    } else {
-                        Slog.e(TAG, "duplicate icon in slot " + slotIndex + "/" + data.slot);
-                        mIconMap.remove(key);
-                        mIconList.remove(icon);
-                        return ;
-                    }
-                } else {
-                    int iconIndex = mNotificationData.getIconIndex(n);
-                    mNotificationIcons.addView(icon.view, iconIndex);
-                }
-            } else {
-                if (n == null) {
-                    // right hand side icons -- these don't reorder
-                    icon.update(mContext, data);
-                } else {
-                    // remove old
-                    ViewGroup parent = (ViewGroup)icon.view.getParent();
-                    parent.removeView(icon.view);
-                    // add new
-                    icon.update(mContext, data);
-                    int iconIndex = mNotificationData.getIconIndex(n);
-                    mNotificationIcons.addView(icon.view, iconIndex);
-                }
-            }
-        }
-    }
-
-    /* private */ void performSetIconVisibility(IBinder key, boolean visible) {
-        synchronized (mIconMap) {
-            if (SPEW) {
-                Slog.d(TAG, "performSetIconVisibility key=" + key + " visible=" + visible);
-            }
-            StatusBarIcon icon = mIconMap.get(key);
-            icon.view.setVisibility(visible ? View.VISIBLE : View.GONE);
-        }
-    }
-    
-    /* private */ void performRemoveIcon(IBinder key) {
-        synchronized (this) {
-            if (SPEW) {
-                Slog.d(TAG, "performRemoveIcon key=" + key);
-            }
-            StatusBarIcon icon = mIconMap.remove(key);
-            mIconList.remove(icon);
-            if (icon != null) {
-                ViewGroup parent = (ViewGroup)icon.view.getParent();
-                parent.removeView(icon.view);
-                int slotIndex = getRightIconIndex(icon.mData.slot);
-                if (slotIndex >= 0) {
-                    mRightIcons[slotIndex] = null;
-                }
-            }
-            StatusBarNotification notification = getNotification(key);
-            if (notification != null) {
-                removeNotificationView(notification);
-                synchronized (mNotificationData) {
-                    mNotificationData.remove(notification);
-                }
-                setAreThereNotifications();
-            }
-        }
-    }
-
-    int getIconNumberForView(View v) {
-        synchronized (mIconMap) {
-            StatusBarIcon icon = null;
-            final int N = mIconList.size();
-            for (int i=0; i<N; i++) {
-                StatusBarIcon ic = mIconList.get(i);
-                if (ic.view == v) {
-                    icon = ic;
-                    break;
-                }
-            }
-            if (icon != null) {
-                return icon.getNumber();
-            } else {
-                return -1;
-            }
-        }
-    }
-
-
-    StatusBarNotification getNotification(IBinder key) {
-        synchronized (mNotificationData) {
-            return mNotificationData.get(key);
-        }
-    }
-
-    View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
-        public void onFocusChange(View v, boolean hasFocus) {
-            // Because 'v' is a ViewGroup, all its children will be (un)selected
-            // too, which allows marqueeing to work.
-            v.setSelected(hasFocus);
-        }
-    };
-    
-    View makeNotificationView(StatusBarNotification notification, ViewGroup parent) {
-        NotificationData n = notification.data;
-        RemoteViews remoteViews = n.contentView;
-        if (remoteViews == null) {
-            return null;
-        }
-
-        // create the row view
-        LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
-                Context.LAYOUT_INFLATER_SERVICE);
-        View row = inflater.inflate(com.android.internal.R.layout.status_bar_latest_event, parent, false);
-
-        // bind the click event to the content area
-        ViewGroup content = (ViewGroup)row.findViewById(com.android.internal.R.id.content);
-        content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-        content.setOnFocusChangeListener(mFocusChangeListener);
-        PendingIntent contentIntent = n.contentIntent;
-        if (contentIntent != null) {
-            content.setOnClickListener(new Launcher(contentIntent, n.pkg, n.tag, n.id));
-        }
-
-        View child = null;
-        Exception exception = null;
-        try {
-            child = remoteViews.apply(mContext, content);
-        }
-        catch (RuntimeException e) {
-            exception = e;
-        }
-        if (child == null) {
-            Slog.e(TAG, "couldn't inflate view for package " + n.pkg, exception);
-            return null;
-        }
-        content.addView(child);
-
-        row.setDrawingCacheEnabled(true);
-
-        notification.view = row;
-        notification.contentView = child;
-
-        return row;
-    }
-
-    void addNotificationView(StatusBarNotification notification) {
-        if (notification.view != null) {
-            throw new RuntimeException("Assertion failed: notification.view="
-                    + notification.view);
-        }
-
-        LinearLayout parent = notification.data.ongoingEvent ? mOngoingItems : mLatestItems;
-
-        View child = makeNotificationView(notification, parent);
-        if (child == null) {
-            return ;
-        }
-
-        int index = mNotificationData.getExpandedIndex(notification);
-        parent.addView(child, index);
-    }
-
-    /**
-     * Remove the old one and put the new one in its place.
-     * @param notification the notification
-     */
-    void updateNotificationView(StatusBarNotification notification, NotificationData oldData) {
-        NotificationData n = notification.data;
-        if (oldData != null && n != null
-                && n.when == oldData.when
-                && n.ongoingEvent == oldData.ongoingEvent
-                && n.contentView != null && oldData.contentView != null
-                && n.contentView.getPackage() != null
-                && oldData.contentView.getPackage() != null
-                && oldData.contentView.getPackage().equals(n.contentView.getPackage())
-                && oldData.contentView.getLayoutId() == n.contentView.getLayoutId()
-                && notification.view != null) {
-            mNotificationData.update(notification);
-            try {
-                n.contentView.reapply(mContext, notification.contentView);
-
-                // update the contentIntent
-                ViewGroup content = (ViewGroup)notification.view.findViewById(
-                        com.android.internal.R.id.content);
-                PendingIntent contentIntent = n.contentIntent;
-                if (contentIntent != null) {
-                    content.setOnClickListener(new Launcher(contentIntent, n.pkg, n.tag, n.id));
-                }
-            }
-            catch (RuntimeException e) {
-                // It failed to add cleanly.  Log, and remove the view from the panel.
-                Slog.w(TAG, "couldn't reapply views for package " + n.contentView.getPackage(), e);
-                removeNotificationView(notification);
-            }
-        } else {
-            mNotificationData.update(notification);
-            removeNotificationView(notification);
-            addNotificationView(notification);
-        }
-        setAreThereNotifications();
-    }
-
-    void removeNotificationView(StatusBarNotification notification) {
-        View v = notification.view;
-        if (v != null) {
-            ViewGroup parent = (ViewGroup)v.getParent();
-            parent.removeView(v);
-            notification.view = null;
-        }
-    }
-
-    private void setAreThereNotifications() {
-        boolean ongoing = mOngoingItems.getChildCount() != 0;
-        boolean latest = mLatestItems.getChildCount() != 0;
-
-        if (mNotificationData.hasClearableItems()) {
-            mClearButton.setVisibility(View.VISIBLE);
-        } else {
-            mClearButton.setVisibility(View.INVISIBLE);
-        }
-
-        mOngoingTitle.setVisibility(ongoing ? View.VISIBLE : View.GONE);
-        mLatestTitle.setVisibility(latest ? View.VISIBLE : View.GONE);
-
-        if (ongoing || latest) {
-            mNoNotificationsTitle.setVisibility(View.GONE);
-        } else {
-            mNoNotificationsTitle.setVisibility(View.VISIBLE);
-        }
-    }
-
-    private void makeExpandedVisible() {
-        if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
-        if (mExpandedVisible) {
-            return;
-        }
-        mExpandedVisible = true;
-        panelSlightlyVisible(true);
-        
-        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-        mExpandedView.requestFocus(View.FOCUS_FORWARD);
-        mTrackingView.setVisibility(View.VISIBLE);
-        
-        if (!mTicking) {
-            setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
-        }
-    }
-    
-    void animateExpand() {
-        if (SPEW) Slog.d(TAG, "Animate expand: expanded=" + mExpanded);
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return ;
-        }
-        if (mExpanded) {
-            return;
-        }
-
-        prepareTracking(0, true);
-        performFling(0, 2000.0f, true);
-    }
-    
-    void animateCollapse() {
-        if (SPEW) {
-            Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
-                    + " mExpandedVisible=" + mExpandedVisible
-                    + " mExpanded=" + mExpanded
-                    + " mAnimating=" + mAnimating
-                    + " mAnimY=" + mAnimY
-                    + " mAnimVel=" + mAnimVel);
-        }
-        
-        if (!mExpandedVisible) {
-            return;
-        }
-
-        int y;
-        if (mAnimating) {
-            y = (int)mAnimY;
-        } else {
-            y = mDisplay.getHeight()-1;
-        }
-        // Let the fling think that we're open so it goes in the right direction
-        // and doesn't try to re-open the windowshade.
-        mExpanded = true;
-        prepareTracking(y, false);
-        performFling(y, -2000.0f, true);
-    }
-    
-    void performExpand() {
-        if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded);
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return ;
-        }
-        if (mExpanded) {
-            return;
-        }
-
-        // It seems strange to sometimes not expand...
-        if (false) {
-            synchronized (mNotificationData) {
-                if (mNotificationData.size() == 0) {
-                    return;
-                }
-            }
-        }
-        
-        mExpanded = true;
-        makeExpandedVisible();
-        updateExpandedViewPos(EXPANDED_FULL_OPEN);
-
-        if (false) postStartTracing();
-    }
-
-    void performCollapse() {
-        if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded
-                + " mExpandedVisible=" + mExpandedVisible);
-        
-        if (!mExpandedVisible) {
-            return;
-        }
-        mExpandedVisible = false;
-        panelSlightlyVisible(false);
-        mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-        mTrackingView.setVisibility(View.GONE);
-
-        if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
-            setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
-        }
-        setDateViewVisibility(false, com.android.internal.R.anim.fade_out);
-        
-        if (!mExpanded) {
-            return;
-        }
-        mExpanded = false;
-    }
-
-    void doAnimation() {
-        if (mAnimating) {
-            if (SPEW) Slog.d(TAG, "doAnimation");
-            if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
-            incrementAnim();
-            if (SPEW) Slog.d(TAG, "doAnimation after  mAnimY=" + mAnimY);
-            if (mAnimY >= mDisplay.getHeight()-1) {
-                if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
-                mAnimating = false;
-                updateExpandedViewPos(EXPANDED_FULL_OPEN);
-                performExpand();
-            }
-            else if (mAnimY < mStatusBarView.getHeight()) {
-                if (SPEW) Slog.d(TAG, "Animation completed to collapsed state.");
-                mAnimating = false;
-                updateExpandedViewPos(0);
-                performCollapse();
-            }
-            else {
-                updateExpandedViewPos((int)mAnimY);
-                mCurAnimationTime += ANIM_FRAME_DURATION;
-                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
-            }
-        }
-    }
-
-    void stopTracking() {
-        mTracking = false;
-        mVelocityTracker.recycle();
-        mVelocityTracker = null;
-    }
-
-    void incrementAnim() {
-        long now = SystemClock.uptimeMillis();
-        float t = ((float)(now - mAnimLastTime)) / 1000;            // ms -> s
-        final float y = mAnimY;
-        final float v = mAnimVel;                                   // px/s
-        final float a = mAnimAccel;                                 // px/s/s
-        mAnimY = y + (v*t) + (0.5f*a*t*t);                          // px
-        mAnimVel = v + (a*t);                                       // px/s
-        mAnimLastTime = now;                                        // ms
-        //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY
-        //        + " mAnimAccel=" + mAnimAccel);
-    }
-
-    void doRevealAnimation() {
-        final int h = mCloseView.getHeight() + mStatusBarView.getHeight();
-        if (mAnimatingReveal && mAnimating && mAnimY < h) {
-            incrementAnim();
-            if (mAnimY >= h) {
-                mAnimY = h;
-                updateExpandedViewPos((int)mAnimY);
-            } else {
-                updateExpandedViewPos((int)mAnimY);
-                mCurAnimationTime += ANIM_FRAME_DURATION;
-                mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
-                        mCurAnimationTime);
-            }
-        }
-    }
-    
-    void prepareTracking(int y, boolean opening) {
-        mTracking = true;
-        mVelocityTracker = VelocityTracker.obtain();
-        if (opening) {
-            mAnimAccel = 2000.0f;
-            mAnimVel = 200;
-            mAnimY = mStatusBarView.getHeight();
-            updateExpandedViewPos((int)mAnimY);
-            mAnimating = true;
-            mAnimatingReveal = true;
-            mHandler.removeMessages(MSG_ANIMATE);
-            mHandler.removeMessages(MSG_ANIMATE_REVEAL);
-            long now = SystemClock.uptimeMillis();
-            mAnimLastTime = now;
-            mCurAnimationTime = now + ANIM_FRAME_DURATION;
-            mAnimating = true;
-            mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL),
-                    mCurAnimationTime);
-            makeExpandedVisible();
-        } else {
-            // it's open, close it?
-            if (mAnimating) {
-                mAnimating = false;
-                mHandler.removeMessages(MSG_ANIMATE);
-            }
-            updateExpandedViewPos(y + mViewDelta);
-        }
-    }
-    
-    void performFling(int y, float vel, boolean always) {
-        mAnimatingReveal = false;
-        mDisplayHeight = mDisplay.getHeight();
-
-        mAnimY = y;
-        mAnimVel = vel;
-
-        //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel);
-
-        if (mExpanded) {
-            if (!always && (
-                    vel > 200.0f
-                    || (y > (mDisplayHeight-25) && vel > -200.0f))) {
-                // We are expanded, but they didn't move sufficiently to cause
-                // us to retract.  Animate back to the expanded position.
-                mAnimAccel = 2000.0f;
-                if (vel < 0) {
-                    mAnimVel = 0;
-                }
-            }
-            else {
-                // We are expanded and are now going to animate away.
-                mAnimAccel = -2000.0f;
-                if (vel > 0) {
-                    mAnimVel = 0;
-                }
-            }
-        } else {
-            if (always || (
-                    vel > 200.0f
-                    || (y > (mDisplayHeight/2) && vel > -200.0f))) {
-                // We are collapsed, and they moved enough to allow us to
-                // expand.  Animate in the notifications.
-                mAnimAccel = 2000.0f;
-                if (vel < 0) {
-                    mAnimVel = 0;
-                }
-            }
-            else {
-                // We are collapsed, but they didn't move sufficiently to cause
-                // us to retract.  Animate back to the collapsed position.
-                mAnimAccel = -2000.0f;
-                if (vel > 0) {
-                    mAnimVel = 0;
-                }
-            }
-        }
-        //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
-        //        + " mAnimAccel=" + mAnimAccel);
-
-        long now = SystemClock.uptimeMillis();
-        mAnimLastTime = now;
-        mCurAnimationTime = now + ANIM_FRAME_DURATION;
-        mAnimating = true;
-        mHandler.removeMessages(MSG_ANIMATE);
-        mHandler.removeMessages(MSG_ANIMATE_REVEAL);
-        mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime);
-        stopTracking();
-    }
-    
-    boolean interceptTouchEvent(MotionEvent event) {
-        if (SPEW) {
-            Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
-                + mDisabled);
-        }
-
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return false;
-        }
-        
-        final int statusBarSize = mStatusBarView.getHeight();
-        final int hitSize = statusBarSize*2;
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            final int y = (int)event.getRawY();
-
-            if (!mExpanded) {
-                mViewDelta = statusBarSize - y;
-            } else {
-                mTrackingView.getLocationOnScreen(mAbsPos);
-                mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y;
-            }
-            if ((!mExpanded && y < hitSize) ||
-                    (mExpanded && y > (mDisplay.getHeight()-hitSize))) {
-
-                // We drop events at the edge of the screen to make the windowshade come
-                // down by accident less, especially when pushing open a device with a keyboard
-                // that rotates (like g1 and droid)
-                int x = (int)event.getRawX();
-                final int edgeBorder = mEdgeBorder;
-                if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) {
-                    prepareTracking(y, !mExpanded);// opening if we're not already fully visible
-                    mVelocityTracker.addMovement(event);
-                }
-            }
-        } else if (mTracking) {
-            mVelocityTracker.addMovement(event);
-            final int minY = statusBarSize + mCloseView.getHeight();
-            if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                int y = (int)event.getRawY();
-                if (mAnimatingReveal && y < minY) {
-                    // nothing
-                } else  {
-                    mAnimatingReveal = false;
-                    updateExpandedViewPos(y + mViewDelta);
-                }
-            } else if (event.getAction() == MotionEvent.ACTION_UP) {
-                mVelocityTracker.computeCurrentVelocity(1000);
-
-                float yVel = mVelocityTracker.getYVelocity();
-                boolean negative = yVel < 0;
-
-                float xVel = mVelocityTracker.getXVelocity();
-                if (xVel < 0) {
-                    xVel = -xVel;
-                }
-                if (xVel > 150.0f) {
-                    xVel = 150.0f; // limit how much we care about the x axis
-                }
-
-                float vel = (float)Math.hypot(yVel, xVel);
-                if (negative) {
-                    vel = -vel;
-                }
-                
-                performFling((int)event.getRawY(), vel, false);
-            }
-            
-        }
-        return false;
-    }
-
-    private class Launcher implements View.OnClickListener {
-        private PendingIntent mIntent;
-        private String mPkg;
-        private String mTag;
-        private int mId;
-
-        Launcher(PendingIntent intent, String pkg, String tag, int id) {
-            mIntent = intent;
-            mPkg = pkg;
-            mTag = tag;
-            mId = id;
-        }
-
-        public void onClick(View v) {
-            try {
-                // The intent we are sending is for the application, which
-                // won't have permission to immediately start an activity after
-                // the user switches to home.  We know it is safe to do at this
-                // point, so make sure new activity switches are now allowed.
-                ActivityManagerNative.getDefault().resumeAppSwitches();
-            } catch (RemoteException e) {
-            }
-            int[] pos = new int[2];
-            v.getLocationOnScreen(pos);
-            Intent overlay = new Intent();
-            overlay.setSourceBounds(
-                    new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
-            try {
-                mIntent.send(mContext, 0, overlay);
-                mNotificationCallbacks.onNotificationClick(mPkg, mTag, mId);
-            } catch (PendingIntent.CanceledException e) {
-                // the stack trace isn't very helpful here.  Just log the exception message.
-                Slog.w(TAG, "Sending contentIntent failed: " + e);
-            }
-            deactivate();
-        }
-    }
-
-    private class MyTicker extends Ticker {
-        MyTicker(Context context, StatusBarView sb) {
-            super(context, sb);
-        }
-        
-        @Override
-        void tickerStarting() {
-            mTicking = true;
-            mIcons.setVisibility(View.GONE);
-            mTickerView.setVisibility(View.VISIBLE);
-            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));
-            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
-            if (mExpandedVisible) {
-                setDateViewVisibility(false, com.android.internal.R.anim.push_up_out);
-            }
-        }
-
-        @Override
-        void tickerDone() {
-            mIcons.setVisibility(View.VISIBLE);
-            mTickerView.setVisibility(View.GONE);
-            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
-            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out,
-                        mTickingDoneListener));
-            if (mExpandedVisible) {
-                setDateViewVisibility(true, com.android.internal.R.anim.push_down_in);
-            }
-        }
-
-        void tickerHalting() {
-            mIcons.setVisibility(View.VISIBLE);
-            mTickerView.setVisibility(View.GONE);
-            mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
-            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out,
-                        mTickingDoneListener));
-            if (mExpandedVisible) {
-                setDateViewVisibility(true, com.android.internal.R.anim.fade_in);
-            }
-        }
-    }
-
-    Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {;
-        public void onAnimationEnd(Animation animation) {
-            mTicking = false;
-        }
-        public void onAnimationRepeat(Animation animation) {
-        }
-        public void onAnimationStart(Animation animation) {
-        }
-    };
-
-    private Animation loadAnim(int id, Animation.AnimationListener listener) {
-        Animation anim = AnimationUtils.loadAnimation(mContext, id);
-        if (listener != null) {
-            anim.setAnimationListener(listener);
-        }
-        return anim;
-    }
-
-    public String viewInfo(View v) {
-        return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
-                + " " + v.getWidth() + "x" + v.getHeight() + ")";
-    }
-
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump StatusBar from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-        
-        synchronized (mQueueLock) {
-            pw.println("Current Status Bar state:");
-            pw.println("  mExpanded=" + mExpanded
-                    + ", mExpandedVisible=" + mExpandedVisible);
-            pw.println("  mTicking=" + mTicking);
-            pw.println("  mTracking=" + mTracking);
-            pw.println("  mAnimating=" + mAnimating
-                    + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel
-                    + ", mAnimAccel=" + mAnimAccel);
-            pw.println("  mCurAnimationTime=" + mCurAnimationTime
-                    + " mAnimLastTime=" + mAnimLastTime);
-            pw.println("  mDisplayHeight=" + mDisplayHeight
-                    + " mAnimatingReveal=" + mAnimatingReveal
-                    + " mViewDelta=" + mViewDelta);
-            pw.println("  mDisplayHeight=" + mDisplayHeight);
-            final int N = mQueue.size();
-            pw.println("  mQueue.size=" + N);
-            for (int i=0; i<N; i++) {
-                PendingOp op = mQueue.get(i);
-                pw.println("    [" + i + "] key=" + op.key + " code=" + op.code + " visible="
-                        + op.visible);
-                pw.println("           iconData=" + op.iconData);
-                pw.println("           notificationData=" + op.notificationData);
-            }
-            pw.println("  mExpandedParams: " + mExpandedParams);
-            pw.println("  mExpandedView: " + viewInfo(mExpandedView));
-            pw.println("  mExpandedDialog: " + mExpandedDialog);
-            pw.println("  mTrackingParams: " + mTrackingParams);
-            pw.println("  mTrackingView: " + viewInfo(mTrackingView));
-            pw.println("  mOngoingTitle: " + viewInfo(mOngoingTitle));
-            pw.println("  mOngoingItems: " + viewInfo(mOngoingItems));
-            pw.println("  mLatestTitle: " + viewInfo(mLatestTitle));
-            pw.println("  mLatestItems: " + viewInfo(mLatestItems));
-            pw.println("  mNoNotificationsTitle: " + viewInfo(mNoNotificationsTitle));
-            pw.println("  mCloseView: " + viewInfo(mCloseView));
-            pw.println("  mTickerView: " + viewInfo(mTickerView));
-            pw.println("  mScrollView: " + viewInfo(mScrollView)
-                    + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
-            pw.println("mNotificationLinearLayout: " + viewInfo(mNotificationLinearLayout));
-        }
-        synchronized (mIconMap) {
-            final int N = mIconMap.size();
-            pw.println("  mIconMap.size=" + N);
-            Set<IBinder> keys = mIconMap.keySet();
-            int i=0;
-            for (IBinder key: keys) {
-                StatusBarIcon icon = mIconMap.get(key);
-                pw.println("    [" + i + "] key=" + key);
-                pw.println("           data=" + icon.mData);
-                i++;
-            }
-        }
-        synchronized (mNotificationData) {
-            int N = mNotificationData.ongoingCount();
-            pw.println("  ongoingCount.size=" + N);
-            for (int i=0; i<N; i++) {
-                StatusBarNotification n = mNotificationData.getOngoing(i);
-                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
-                pw.println("           data=" + n.data);
-            }
-            N = mNotificationData.latestCount();
-            pw.println("  ongoingCount.size=" + N);
-            for (int i=0; i<N; i++) {
-                StatusBarNotification n = mNotificationData.getLatest(i);
-                pw.println("    [" + i + "] key=" + n.key + " view=" + n.view);
-                pw.println("           data=" + n.data);
-            }
-        }
-        synchronized (mDisableRecords) {
-            final int N = mDisableRecords.size();
-            pw.println("  mDisableRecords.size=" + N
-                    + " mDisabled=0x" + Integer.toHexString(mDisabled));
-            for (int i=0; i<N; i++) {
-                DisableRecord tok = mDisableRecords.get(i);
-                pw.println("    [" + i + "] what=0x" + Integer.toHexString(tok.what)
-                                + " pkg=" + tok.pkg + " token=" + tok.token);
-            }
-        }
-        
-        if (false) {
-            pw.println("see the logcat for a dump of the views we have created.");
-            // must happen on ui thread
-            mHandler.post(new Runnable() {
-                    public void run() {
-                        mStatusBarView.getLocationOnScreen(mAbsPos);
-                        Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
-                                + ") " + mStatusBarView.getWidth() + "x"
-                                + mStatusBarView.getHeight());
-                        mStatusBarView.debug();
-
-                        mExpandedView.getLocationOnScreen(mAbsPos);
-                        Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
-                                + ") " + mExpandedView.getWidth() + "x"
-                                + mExpandedView.getHeight());
-                        mExpandedView.debug();
-
-                        mTrackingView.getLocationOnScreen(mAbsPos);
-                        Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
-                                + ") " + mTrackingView.getWidth() + "x"
-                                + mTrackingView.getHeight());
-                        mTrackingView.debug();
-                    }
-                });
-        }
-    }
-
-    void onBarViewAttached() {
-        WindowManager.LayoutParams lp;
-        int pixelFormat;
-        Drawable bg;
-
-        /// ---------- Tracking View --------------
-        pixelFormat = PixelFormat.RGBX_8888;
-        bg = mTrackingView.getBackground();
-        if (bg != null) {
-            pixelFormat = bg.getOpacity();
-        }
-
-        lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
-                pixelFormat);
-//        lp.token = mStatusBarView.getWindowToken();
-        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        lp.setTitle("TrackingView");
-        lp.y = mTrackingPosition;
-        mTrackingParams = lp;
-
-        WindowManagerImpl.getDefault().addView(mTrackingView, lp);
-    }
-
-    void onTrackingViewAttached() {
-        WindowManager.LayoutParams lp;
-        int pixelFormat;
-        Drawable bg;
-
-        /// ---------- Expanded View --------------
-        pixelFormat = PixelFormat.TRANSLUCENT;
-
-        final int disph = mDisplay.getHeight();
-        lp = mExpandedDialog.getWindow().getAttributes();
-        lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
-        lp.height = getExpandedHeight();
-        lp.x = 0;
-        mTrackingPosition = lp.y = -disph; // sufficiently large negative
-        lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
-        lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | WindowManager.LayoutParams.FLAG_DITHER
-                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        lp.format = pixelFormat;
-        lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        lp.setTitle("StatusBarExpanded");
-        mExpandedDialog.getWindow().setAttributes(lp);
-        mExpandedDialog.getWindow().setFormat(pixelFormat);
-        mExpandedParams = lp;
-
-        mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
-        mExpandedDialog.setContentView(mExpandedView,
-                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
-                                           ViewGroup.LayoutParams.MATCH_PARENT));
-        mExpandedDialog.getWindow().setBackgroundDrawable(null);
-        mExpandedDialog.show();
-        FrameLayout hack = (FrameLayout)mExpandedView.getParent();
-    }
-
-    void setDateViewVisibility(boolean visible, int anim) {
-        mDateView.setUpdates(visible);
-        mDateView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
-        mDateView.startAnimation(loadAnim(anim, null));
-    }
-
-    void setNotificationIconVisibility(boolean visible, int anim) {
-        int old = mNotificationIcons.getVisibility();
-        int v = visible ? View.VISIBLE : View.INVISIBLE;
-        if (old != v) {
-            mNotificationIcons.setVisibility(v);
-            mNotificationIcons.startAnimation(loadAnim(anim, null));
-        }
-    }
-
-    void updateExpandedViewPos(int expandedPosition) {
-        if (SPEW) {
-            Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
-                    + " mTrackingParams.y=" + mTrackingParams.y
-                    + " mTrackingPosition=" + mTrackingPosition);
-        }
-
-        int h = mStatusBarView.getHeight();
-        int disph = mDisplay.getHeight();
-
-        // If the expanded view is not visible, make sure they're still off screen.
-        // Maybe the view was resized.
-        if (!mExpandedVisible) {
-            if (mTrackingView != null) {
-                mTrackingPosition = -disph;
-                if (mTrackingParams != null) {
-                    mTrackingParams.y = mTrackingPosition;
-                    WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
-                }
-            }
-            if (mExpandedParams != null) {
-                mExpandedParams.y = -disph;
-                mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-            }
-            return;
-        }
-
-        // tracking view...
-        int pos;
-        if (expandedPosition == EXPANDED_FULL_OPEN) {
-            pos = h;
-        }
-        else if (expandedPosition == EXPANDED_LEAVE_ALONE) {
-            pos = mTrackingPosition;
-        }
-        else {
-            if (expandedPosition <= disph) {
-                pos = expandedPosition;
-            } else {
-                pos = disph;
-            }
-            pos -= disph-h;
-        }
-        mTrackingPosition = mTrackingParams.y = pos;
-        mTrackingParams.height = disph-h;
-        WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
-
-        if (mExpandedParams != null) {
-            mCloseView.getLocationInWindow(mPositionTmp);
-            final int closePos = mPositionTmp[1];
-
-            mExpandedContents.getLocationInWindow(mPositionTmp);
-            final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
-
-            mExpandedParams.y = pos + mTrackingView.getHeight()
-                    - (mTrackingParams.height-closePos) - contentsBottom;
-            int max = h;
-            if (mExpandedParams.y > max) {
-                mExpandedParams.y = max;
-            }
-            int min = mTrackingPosition;
-            if (mExpandedParams.y < min) {
-                mExpandedParams.y = min;
-            }
-
-            boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h;
-            if (!visible) {
-                // if the contents aren't visible, move the expanded view way off screen
-                // because the window itself extends below the content view.
-                mExpandedParams.y = -disph;
-            }
-            panelSlightlyVisible(visible);
-            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-        }
-
-        if (SPEW) {
-            Slog.d(TAG, "updateExpandedViewPos after  expandedPosition=" + expandedPosition
-                    + " mTrackingParams.y=" + mTrackingParams.y
-                    + " mTrackingPosition=" + mTrackingPosition
-                    + " mExpandedParams.y=" + mExpandedParams.y
-                    + " mExpandedParams.height=" + mExpandedParams.height);
-        }
-    }
-
-    int getExpandedHeight() {
-        return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight();
-    }
-
-    void updateExpandedHeight() {
-        if (mExpandedView != null) {
-            mExpandedParams.height = getExpandedHeight();
-            mExpandedDialog.getWindow().setAttributes(mExpandedParams);
-        }
-    }
-
-    /**
-     * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
-     * This was added last-minute and is inconsistent with the way the rest of the notifications
-     * are handled, because the notification isn't really cancelled.  The lights are just
-     * turned off.  If any other notifications happen, the lights will turn back on.  Steve says
-     * this is what he wants. (see bug 1131461)
-     */
-    private boolean mPanelSlightlyVisible;
-    void panelSlightlyVisible(boolean visible) {
-        if (mPanelSlightlyVisible != visible) {
-            mPanelSlightlyVisible = visible;
-            if (visible) {
-                // tell the notification manager to turn off the lights.
-                mNotificationCallbacks.onPanelRevealed();
-            }
-        }
-    }
-
-    void performDisableActions(int net) {
-        int old = mDisabled;
-        int diff = net ^ old;
-        mDisabled = net;
-
-        // act accordingly
-        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
-            if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
-                Slog.d(TAG, "DISABLE_EXPAND: yes");
-                animateCollapse();
-            }
-        }
-        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-            if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
-                if (mTicking) {
-                    mNotificationIcons.setVisibility(View.INVISIBLE);
-                    mTicker.halt();
-                } else {
-                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
-                }
-            } else {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
-                if (!mExpandedVisible) {
-                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
-                }
-            }
-        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-            if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-                mTicker.halt();
-            }
-        }
-    }
-
-    private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            mNotificationCallbacks.onClearAll();
-            addPendingOp(OP_EXPAND, null, false);
-        }
-    };
-
-    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
-                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
-                deactivate();
-            }
-            else if (Telephony.Intents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
-                updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false),
-                        intent.getStringExtra(Telephony.Intents.EXTRA_SPN),
-                        intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false),
-                        intent.getStringExtra(Telephony.Intents.EXTRA_PLMN));
-            }
-            else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-                updateResources();
-            }
-        }
-    };
-
-    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
-        if (false) {
-            Slog.d(TAG, "updateNetworkName showSpn=" + showSpn + " spn=" + spn
-                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
-        }
-        boolean something = false;
-        if (showPlmn) {
-            mPlmnLabel.setVisibility(View.VISIBLE);
-            if (plmn != null) {
-                mPlmnLabel.setText(plmn);
-            } else {
-                mPlmnLabel.setText(R.string.lockscreen_carrier_default);
-            }
-        } else {
-            mPlmnLabel.setText("");
-            mPlmnLabel.setVisibility(View.GONE);
-        }
-        if (showSpn && spn != null) {
-            mSpnLabel.setText(spn);
-            mSpnLabel.setVisibility(View.VISIBLE);
-            something = true;
-        } else {
-            mSpnLabel.setText("");
-            mSpnLabel.setVisibility(View.GONE);
-        }
-    }
-
-    /**
-     * Reload some of our resources when the configuration changes.
-     * 
-     * We don't reload everything when the configuration changes -- we probably
-     * should, but getting that smooth is tough.  Someday we'll fix that.  In the
-     * meantime, just update the things that we know change.
-     */
-    void updateResources() {
-        Resources res = mContext.getResources();
-
-        mClearButton.setText(mContext.getText(R.string.status_bar_clear_all_button));
-        mOngoingTitle.setText(mContext.getText(R.string.status_bar_ongoing_events_title));
-        mLatestTitle.setText(mContext.getText(R.string.status_bar_latest_events_title));
-        mNoNotificationsTitle.setText(mContext.getText(R.string.status_bar_no_notifications_title));
-
-        mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
-
-        if (false) Slog.v(TAG, "updateResources");
-    }
-
-    //
-    // tracing
-    //
-
-    void postStartTracing() {
-        mHandler.postDelayed(mStartTracing, 3000);
-    }
-
-    void vibrate() {
-        android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService(
-                Context.VIBRATOR_SERVICE);
-        vib.vibrate(250);
-    }
-
-    Runnable mStartTracing = new Runnable() {
-        public void run() {
-            vibrate();
-            SystemClock.sleep(250);
-            Slog.d(TAG, "startTracing");
-            android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
-            mHandler.postDelayed(mStopTracing, 10000);
-        }
-    };
-
-    Runnable mStopTracing = new Runnable() {
-        public void run() {
-            android.os.Debug.stopMethodTracing();
-            Slog.d(TAG, "stopTracing");
-            vibrate();
-        }
-    };
-    
-    class UninstallReceiver extends BroadcastReceiver {
-        public UninstallReceiver() {
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-            filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
-            filter.addDataScheme("package");
-            mContext.registerReceiver(this, filter);
-            IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-            mContext.registerReceiver(this, sdFilter);
-        }
-        
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String pkgList[] = null;
-            if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) {
-                pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
-            } else {
-                Uri data = intent.getData();
-                if (data != null) {
-                    String pkg = data.getSchemeSpecificPart();
-                    if (pkg != null) {
-                        pkgList = new String[]{pkg};
-                    }
-                }
-            }
-            ArrayList<StatusBarNotification> list = null;
-            if (pkgList != null) {
-                synchronized (StatusBarService.this) {
-                    for (String pkg : pkgList) {
-                        list = mNotificationData.notificationsForPackage(pkg);
-                    }
-                }
-            }
-            
-            if (list != null) {
-                final int N = list.size();
-                for (int i=0; i<N; i++) {
-                    removeIcon(list.get(i).key);
-                }
-            }
-        }
-    }
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
index 4cbfc87..05527af 100644
--- a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
+++ b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
@@ -55,6 +55,35 @@
         this.types = types;
     }
 
+    // data[0] = name
+    // data[1] = apn
+    // data[2] = proxy
+    // data[3] = port
+    // data[4] = username
+    // data[5] = password
+    // data[6] = server
+    // data[7] = mmsc
+    // data[8] = mmsproxy
+    // data[9] = mmsport
+    // data[10] = mcc
+    // data[11] = mnc
+    // data[12] = auth
+    // data[13] = first type...
+    public static ApnSetting fromString(String data) {
+        if (data == null) return null;
+        String[] a = data.split("\\s*,\\s*");
+        if (a.length < 14) return null;
+        int authType = 0;
+        try {
+            authType = Integer.parseInt(a[12]);
+        } catch (Exception e) {
+        }
+        String[] typeArray = new String[a.length - 13];
+        System.arraycopy(a, 13, typeArray, 0, a.length - 13);
+        return new ApnSetting(-1,a[10]+a[11],a[0],a[1],a[2],a[3],a[7],a[8],
+                a[9],a[4],a[5],authType,typeArray);
+    }
+
     public String toString() {
         StringBuilder sb = new StringBuilder();
         sb.append(carrier)
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 9bc0b26..f6d4491 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -48,6 +48,7 @@
 import android.util.EventLog;
 import android.util.Log;
 
+import com.android.internal.R;
 import com.android.internal.telephony.DataCallState;
 import com.android.internal.telephony.DataConnection;
 import com.android.internal.telephony.DataConnectionTracker;
@@ -365,6 +366,10 @@
 
     @Override
     protected boolean isApnTypeAvailable(String type) {
+        if (type.equals(Phone.APN_TYPE_DUN)) {
+            return (fetchDunApn() != null);
+        }
+
         if (allApns != null) {
             for (ApnSetting apn : allApns) {
                 if (apn.canHandleType(type)) {
@@ -1302,6 +1307,17 @@
         }
     }
 
+    private ApnSetting fetchDunApn() {
+        Context c = phone.getContext();
+        String apnData = Settings.Secure.getString(c.getContentResolver(),
+                                    Settings.Secure.TETHER_DUN_APN);
+        ApnSetting dunSetting = ApnSetting.fromString(apnData);
+        if (dunSetting != null) return dunSetting;
+
+        apnData = c.getResources().getString(R.string.config_tether_apndata);
+        return ApnSetting.fromString(apnData);
+    }
+
     /**
      *
      * @return waitingApns list to be used to create PDP
@@ -1309,6 +1325,13 @@
      */
     private ArrayList<ApnSetting> buildWaitingApns() {
         ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>();
+
+        if (mRequestedApnType.equals(Phone.APN_TYPE_DUN)) {
+            ApnSetting dun = fetchDunApn();
+            if (dun != null) apnList.add(dun);
+            return apnList;
+        }
+
         String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric();
 
         if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index a6124bf..3602fec 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -122,6 +122,16 @@
             }
         },
 
+        new Test("Bad Icon") {
+            public void run() {
+                mNM.notify(1, new Notification(NotificationTestList.this,
+                            R.layout.chrono_notification, /* not a drawable! */
+                            null, System.currentTimeMillis()-(1000*60*60*24),
+                            "(453) 123-2328",
+                            "", null));
+            }
+        },
+
         new Test("Bad resource #2") {
             public void run()
             {
@@ -181,7 +191,7 @@
                                 R.drawable.icon4,
                                 null, System.currentTimeMillis(), "Stress - Latest",
                                 "Notify me!!!", null);
-                        n.flags |= Notification.FLAG_ONGOING_EVENT;
+                        //n.flags |= Notification.FLAG_ONGOING_EVENT;
                         mNM.notify(1, n);
                     }
                 }
@@ -623,9 +633,7 @@
 
     private PendingIntent makeIntent() {
         Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setComponent(new android.content.ComponentName(
-                    "com.android.contacts",
-                    "com.android.contacts.ContactsActivity"));
+        intent.addCategory(Intent.CATEGORY_HOME);
         return PendingIntent.getActivity(this, 0, intent, 0);
     }
 
diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
index 06506fb..3532e30 100644
--- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
@@ -134,13 +134,9 @@
                     }, 3000);
             }
         },
-        new Test("Expand in 3 sec.") {
+        new Test("Expand") {
             public void run() {
-                mHandler.postDelayed(new Runnable() {
-                        public void run() {
-                            mStatusBarManager.expand();
-                        }
-                    }, 3000);
+                mStatusBarManager.expand();
             }
         },
         new Test("Expand in 3 sec.") {
@@ -161,14 +157,5 @@
                     }, 3000);
             }
         },
-        new Test("Toggle in 3 sec.") {
-            public void run() {
-                mHandler.postDelayed(new Runnable() {
-                        public void run() {
-                            mStatusBarManager.toggle();
-                        }
-                    }, 3000);
-            }
-        },
     };
 }
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 4d2d046..d6cfb12 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -893,6 +893,11 @@
         return true;
     }
     
+    if (strcmp(name, "xhdpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_MEDIUM*2;
+        return true;
+    }
+    
     char* c = (char*)name;
     while (*c >= '0' && *c <= '9') {
         c++;
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index a2f085a..755b93b 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -573,6 +573,7 @@
                         const String16& parentIdent,
                         const String16& itemIdent,
                         int32_t curFormat,
+                        bool isFormatted,
                         bool pseudolocalize,
                         const bool overwrite,
                         ResourceTable* outTable)
@@ -583,7 +584,7 @@
     String16 str;
     Vector<StringPool::entry_style_span> spans;
     err = parseStyledString(bundle, in->getPrintableSource().string(),
-                            block, item16, &str, &spans,
+                            block, item16, &str, &spans, isFormatted,
                             pseudolocalize);
     if (err != NO_ERROR) {
         return err;
@@ -616,6 +617,7 @@
                         const String16& curTag,
                         bool curIsStyled,
                         int32_t curFormat,
+                        bool isFormatted,
                         bool pseudolocalize,
                         const bool overwrite,
                         ResourceTable* outTable)
@@ -626,7 +628,7 @@
     Vector<StringPool::entry_style_span> spans;
     err = parseStyledString(bundle, in->getPrintableSource().string(), block,
                             curTag, &str, curIsStyled ? &spans : NULL,
-                            pseudolocalize);
+                            isFormatted, pseudolocalize);
 
     if (err < NO_ERROR) { 
         return err;
@@ -709,12 +711,18 @@
     // useful attribute names and special values
     const String16 name16("name");
     const String16 translatable16("translatable");
+    const String16 formatted16("formatted");
     const String16 false16("false");
 
     const String16 myPackage(assets->getPackage());
 
     bool hasErrors = false;
-    
+
+    bool fileIsTranslatable = true;
+    if (strstr(in->getPrintableSource().string(), "donottranslate") != NULL) {
+        fileIsTranslatable = false;
+    }
+
     DefaultKeyedVector<String16, uint32_t> nextPublicId(0);
 
     ResXMLTree::event_code_t code;
@@ -751,6 +759,7 @@
             bool curIsBagReplaceOnOverwrite = false;
             bool curIsStyled = false;
             bool curIsPseudolocalizable = false;
+            bool curIsFormatted = fileIsTranslatable;
             bool localHasErrors = false;
 
             if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
@@ -1136,6 +1145,7 @@
                 String8 locale(rawLocale);
                 String16 name;
                 String16 translatable;
+                String16 formatted;
 
                 size_t n = block.getAttributeCount();
                 for (size_t i = 0; i < n; i++) {
@@ -1145,11 +1155,14 @@
                         name.setTo(block.getAttributeStringValue(i, &length));
                     } else if (strcmp16(attr, translatable16.string()) == 0) {
                         translatable.setTo(block.getAttributeStringValue(i, &length));
+                    } else if (strcmp16(attr, formatted16.string()) == 0) {
+                        formatted.setTo(block.getAttributeStringValue(i, &length));
                     }
                 }
                 
                 if (name.size() > 0) {
                     if (translatable == false16) {
+                        curIsFormatted = false;
                         // Untranslatable strings must only exist in the default [empty] locale
                         if (locale.size() > 0) {
                             fprintf(stderr, "aapt: warning: string '%s' in %s marked untranslatable but exists"
@@ -1167,6 +1180,10 @@
                     } else {
                         outTable->addLocalization(name, locale);
                     }
+
+                    if (formatted == false16) {
+                        curIsFormatted = false;
+                    }
                 }
 
                 curTag = &string16;
@@ -1356,7 +1373,7 @@
                         block.getPosition(&parserPosition);
 
                         err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType,
-                                ident, parentIdent, itemIdent, curFormat, 
+                                ident, parentIdent, itemIdent, curFormat, curIsFormatted,
                                 false, overwrite, outTable);
                         if (err == NO_ERROR) {
                             if (curIsPseudolocalizable && localeIsDefined(curParams)
@@ -1365,8 +1382,8 @@
 #if 1
                                 block.setPosition(parserPosition);
                                 err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage,
-                                        curType, ident, parentIdent, itemIdent, curFormat, true,
-                                        overwrite, outTable);
+                                        curType, ident, parentIdent, itemIdent, curFormat,
+                                        curIsFormatted, true, overwrite, outTable);
 #endif
                             }
                         } 
@@ -1389,7 +1406,8 @@
                 block.getPosition(&parserPosition);
 
                 err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident,
-                        *curTag, curIsStyled, curFormat, false, overwrite, outTable);
+                        *curTag, curIsStyled, curFormat, curIsFormatted,
+                        false, overwrite, outTable);
 
                 if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR?
                     hasErrors = localHasErrors = true;
@@ -1400,7 +1418,8 @@
                         // pseudolocalize here
                         block.setPosition(parserPosition);
                         err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType,
-                                ident, *curTag, curIsStyled, curFormat, true, overwrite, outTable);
+                                ident, *curTag, curIsStyled, curFormat,
+                                curIsFormatted, true, overwrite, outTable);
                         if (err != NO_ERROR) {
                             hasErrors = localHasErrors = true;
                         }
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 4c59288..57ff47a 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -68,12 +68,118 @@
     return String16(namespaceUri, namespaceUri.size()-prefixSize, prefixSize);
 }
 
+status_t hasSubstitutionErrors(const char* fileName,
+                               ResXMLTree* inXml,
+                               String16 str16)
+{
+    const char16_t* str = str16.string();
+    const char16_t* p = str;
+    const char16_t* end = str + str16.size();
+
+    bool nonpositional = false;
+    int argCount = 0;
+
+    while (p < end) {
+        /*
+         * Look for the start of a Java-style substitution sequence.
+         */
+        if (*p == '%' && p + 1 < end) {
+            p++;
+
+            // A literal percent sign represented by %%
+            if (*p == '%') {
+                p++;
+                continue;
+            }
+
+            argCount++;
+
+            if (*p >= '0' && *p <= '9') {
+                do {
+                    p++;
+                } while (*p >= '0' && *p <= '9');
+                if (*p != '$') {
+                    // This must be a size specification instead of position.
+                    nonpositional = true;
+                }
+            } else if (*p == '<') {
+                // Reusing last argument; bad idea since it can be re-arranged.
+                nonpositional = true;
+                p++;
+
+                // Optionally '$' can be specified at the end.
+                if (p < end && *p == '$') {
+                    p++;
+                }
+            } else {
+                nonpositional = true;
+            }
+
+            // Ignore flags and widths
+            while (p < end && (*p == '-' ||
+                    *p == '#' ||
+                    *p == '+' ||
+                    *p == ' ' ||
+                    *p == ',' ||
+                    *p == '(' ||
+                    (*p >= '0' && *p <= '9'))) {
+                p++;
+            }
+
+            /*
+             * This is a shortcut to detect strings that are going to Time.format()
+             * instead of String.format()
+             *
+             * Comparison of String.format() and Time.format() args:
+             *
+             * String: ABC E GH  ST X abcdefgh  nost x
+             *   Time:    DEFGHKMS W Za  d   hkm  s w yz
+             *
+             * Therefore we know it's definitely Time if we have:
+             *     DFKMWZkmwyz
+             */
+            if (p < end) {
+                switch (*p) {
+                case 'D':
+                case 'F':
+                case 'K':
+                case 'M':
+                case 'W':
+                case 'Z':
+                case 'k':
+                case 'm':
+                case 'w':
+                case 'y':
+                case 'z':
+                    return NO_ERROR;
+                }
+            }
+        }
+
+        p++;
+    }
+
+    /*
+     * If we have more than one substitution in this string and any of them
+     * are not in positional form, give the user an error.
+     */
+    if (argCount > 1 && nonpositional) {
+        SourcePos(String8(fileName), inXml->getLineNumber()).error(
+                "Multiple substitutions specified in non-positional format; "
+                "did you mean to add the formatted=\"true\" attribute?\n");
+        return NOT_ENOUGH_DATA;
+    }
+
+    return NO_ERROR;
+}
+
 status_t parseStyledString(Bundle* bundle,
                            const char* fileName,
                            ResXMLTree* inXml,
                            const String16& endTag,
                            String16* outString,
                            Vector<StringPool::entry_style_span>* outSpans,
+                           bool isFormatted,
                            bool pseudolocalize)
 {
     Vector<StringPool::entry_style_span> spanStack;
@@ -101,7 +207,11 @@
                 std::string pseudo = pseudolocalize_string(orig);
                 curString.append(String16(String8(pseudo.c_str())));
             } else {
-                curString.append(text);
+                if (isFormatted && hasSubstitutionErrors(fileName, inXml, text) != NO_ERROR) {
+                    return UNKNOWN_ERROR;
+                } else {
+                    curString.append(text);
+                }
             }
         } else if (code == ResXMLTree::START_TAG) {
             const String16 element16(inXml->getElementName(&len));
diff --git a/tools/aapt/XMLNode.h b/tools/aapt/XMLNode.h
index e9a263b..05624b7 100644
--- a/tools/aapt/XMLNode.h
+++ b/tools/aapt/XMLNode.h
@@ -25,6 +25,7 @@
                            const String16& endTag,
                            String16* outString,
                            Vector<StringPool::entry_style_span>* outSpans,
+                           bool isFormatted,
                            bool isPseudolocalizable);
 
 void printXMLBlock(ResXMLTree* block);