Merge "Add YV12 preview format to camera parameter constants."
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 337b30f..6f9a1e1 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -90,6 +90,10 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libstagefright_aacdec_intermediates)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libstagefright_mp3dec_intermediates)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/build.prop)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/ImageProcessing_intermediates/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/ModelViewer_intermediates/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/PerfTest_intermediates/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/RSTest_intermediates/)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/api/current.xml b/api/current.xml
index 480ad93..cd827a6 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -9937,6 +9937,17 @@
  visibility="public"
 >
 </field>
+<field name="textCursorDrawable"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843618"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="textEditNoPasteWindowLayout"
  type="int"
  transient="false"
@@ -35329,6 +35340,17 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_NEW_SEARCH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;new_search&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="EXTRA_SELECT_QUERY"
  type="java.lang.String"
  transient="false"
@@ -77563,6 +77585,23 @@
  visibility="public"
 >
 </method>
+<method name="rotate"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="x" type="float">
+</parameter>
+<parameter name="y" type="float">
+</parameter>
+<parameter name="z" type="float">
+</parameter>
+</method>
 <method name="rotateX"
  return="void"
  abstract="false"
@@ -77613,6 +77652,23 @@
  visibility="public"
 >
 </method>
+<method name="setLocation"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="x" type="float">
+</parameter>
+<parameter name="y" type="float">
+</parameter>
+<parameter name="z" type="float">
+</parameter>
+</method>
 <method name="translate"
  return="void"
  abstract="false"
@@ -156111,6 +156167,17 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_CREATE_NEW_TAB"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;create_new_tab&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="EXTRA_HEADERS"
  type="java.lang.String"
  transient="false"
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 2e44d6d..b963117 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -902,6 +902,7 @@
         if (mStartDelay == 0) {
             // This sets the initial value of the animation, prior to actually starting it running
             setCurrentPlayTime(getCurrentPlayTime());
+            mPlayingState = STOPPED;
 
             if (mListeners != null) {
                 ArrayList<AnimatorListener> tmpListeners =
diff --git a/core/java/android/animation/package.html b/core/java/android/animation/package.html
index ff43260..92eeb20 100644
--- a/core/java/android/animation/package.html
+++ b/core/java/android/animation/package.html
@@ -15,7 +15,7 @@
 
 <p>
 For a guide on how to use the property animation system, see the
-<a href="{@docRoot}guide/topics/media/index.html">Animation</a> developer guide.
+<a href="{@docRoot}guide/topics/graphics/animation.html">Animation</a> developer guide.
 </p>
 </body>
 </html>
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a660076..77dc084 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -30,11 +30,17 @@
 import android.os.Handler;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
+import android.util.Log;
+import com.android.internal.app.IUsageStats;
+import com.android.internal.os.PkgUsageStats;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Interact with the overall activities running in the system.
@@ -1233,4 +1239,29 @@
     public static boolean isRunningInTestHarness() {
         return SystemProperties.getBoolean("ro.test_harness", false);
     }
+
+    /**
+     * Returns the launch count of each installed package.
+     *
+     * @hide
+     */
+    public Map<String, Integer> getAllPackageLaunchCounts() {
+        try {
+            IUsageStats usageStatsService = IUsageStats.Stub.asInterface(
+                    ServiceManager.getService("usagestats"));
+            if (usageStatsService == null) {
+                return new HashMap<String, Integer>();
+            }
+
+            Map<String, Integer> launchCounts = new HashMap<String, Integer>();
+            for (PkgUsageStats pkgUsageStats : usageStatsService.getAllPkgUsageStats()) {
+                launchCounts.put(pkgUsageStats.packageName, pkgUsageStats.launchCount);
+            }
+
+            return launchCounts;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Could not query launch counts", e);
+            return new HashMap<String, Integer>();
+        }
+    }
 }
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index e3d8e20..1e8743c 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -117,6 +117,40 @@
     }
 
     /**
+     * isKeyguardLocked
+     *
+     * Return whether the keyguard is currently locked.
+     *
+     * @return true if in keyguard is locked.
+     *
+     * @hide
+     */
+    public boolean isKeyguardLocked() {
+        try {
+            return mWM.isKeyguardSecure();
+        } catch (RemoteException ex) {
+            return false;
+        }
+    }
+
+    /**
+     * isKeyguardSecure
+     *
+     * Return whether the keyguard requires a password to unlock.
+     *
+     * @return true if in keyguard is secure.
+     *
+     * @hide
+     */
+    public boolean isKeyguardSecure() {
+        try {
+            return mWM.isKeyguardSecure();
+        } catch (RemoteException ex) {
+            return false;
+        }
+    }
+
+    /**
      * If keyguard screen is showing or in restricted key input mode (i.e. in
      * keyguard password emergency screen). When in such mode, certain keys,
      * such as the Home key and the right soft keys, don't work.
diff --git a/core/java/android/app/ListActivity.java b/core/java/android/app/ListActivity.java
index d49968f..2162521 100644
--- a/core/java/android/app/ListActivity.java
+++ b/core/java/android/app/ListActivity.java
@@ -43,7 +43,7 @@
  * <p>
  * Optionally, your custom view can contain another view object of any type to
  * display when the list view is empty. This "empty list" notifier must have an
- * id "android:empty". Note that when an empty view is present, the list view
+ * id "android:id/empty". Note that when an empty view is present, the list view
  * will be hidden when there is no data to display.
  * <p>
  * The following code demonstrates an (ugly) custom screen layout. It has a list
@@ -59,14 +59,14 @@
  *         android:paddingLeft=&quot;8dp&quot;
  *         android:paddingRight=&quot;8dp&quot;&gt;
  *
- *     &lt;ListView android:id=&quot;@id/android:list&quot;
+ *     &lt;ListView android:id=&quot;@android:id/list&quot;
  *               android:layout_width=&quot;match_parent&quot;
  *               android:layout_height=&quot;match_parent&quot;
  *               android:background=&quot;#00FF00&quot;
  *               android:layout_weight=&quot;1&quot;
  *               android:drawSelectorOnTop=&quot;false&quot;/&gt;
  *
- *     &lt;TextView android:id=&quot;@id/android:empty&quot;
+ *     &lt;TextView android:id=&quot;@android:id/empty&quot;
  *               android:layout_width=&quot;match_parent&quot;
  *               android:layout_height=&quot;match_parent&quot;
  *               android:background=&quot;#FF0000&quot;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 4370ebf..ccd65de 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -82,6 +82,7 @@
 
     /**
      * The resource id of a drawable to use as the icon in the status bar.
+     * This is required; notifications with an invalid icon resource will not be shown.
      */
     public int icon;
 
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index e3242c1..6541c54 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -83,12 +83,14 @@
     }
 
     /**
-     * Persistent notification on the status bar, 
+     * Post a notification to be shown in the status bar. If a notification with
+     * the same id has already been posted by your application and has not yet been canceled, it
+     * will be replaced by the updated information.
      *
      * @param id An identifier for this notification unique within your
      *        application.
-     * @param notification A {@link Notification} object describing how to
-     *        notify the user, other than the view you're providing. Must not be null.
+     * @param notification A {@link Notification} object describing what to show the user. Must not
+     *        be null.
      */
     public void notify(int id, Notification notification)
     {
@@ -96,13 +98,15 @@
     }
 
     /**
-     * Persistent notification on the status bar,
+     * Post a notification to be shown in the status bar. If a notification with
+     * the same tag and id has already been posted by your application and has not yet been
+     * canceled, it will be replaced by the updated information.
      *
      * @param tag A string identifier for this notification.  May be {@code null}.
      * @param id An identifier for this notification.  The pair (tag, id) must be unique
      *        within your application.
-     * @param notification A {@link Notification} object describing how to
-     *        notify the user, other than the view you're providing. Must not be null.
+     * @param notification A {@link Notification} object describing what to
+     *        show the user. Must not be null.
      */
     public void notify(String tag, int id, Notification notification)
     {
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 6715012..aab087f 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -138,6 +138,12 @@
     public final static String EXTRA_SELECT_QUERY = "select_query";
 
     /**
+     * Boolean extra data key for {@link Intent#ACTION_WEB_SEARCH} intents.  If {@code true},
+     * this search should open a new browser window, rather than using an existing one.
+     */
+    public final static String EXTRA_NEW_SEARCH = "new_search";
+
+    /**
      * Boolean extra data key for a suggestion provider to return in {@link Cursor#getExtras} to
      * indicate that the search is not complete yet. This can be used by the search UI
      * to indicate that a search is in progress. The suggestion provider can return partial results
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 4656e15..e1c9044 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1049,6 +1049,12 @@
         } else if (profile == BluetoothProfile.A2DP) {
             BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
             return true;
+        } else if (profile == BluetoothProfile.INPUT_DEVICE) {
+            BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
+            return true;
+        } else if (profile == BluetoothProfile.PAN) {
+            BluetoothPan pan = new BluetoothPan(context, listener);
+            return true;
         } else {
             return false;
         }
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index 6ec347f..116a068 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -136,17 +136,17 @@
                     newState == BluetoothProfile.STATE_DISCONNECTED) {
                     sendMessage(TRANSITION_TO_STABLE);
                 }
-            } else if (action.equals(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED)) {
-                int newState = intent.getIntExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, 0);
+            } else if (action.equals(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED)) {
+                int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
                 int oldState =
-                    intent.getIntExtra(BluetoothInputDevice.EXTRA_PREVIOUS_INPUT_DEVICE_STATE, 0);
+                    intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
 
-                if (oldState == BluetoothInputDevice.STATE_CONNECTED &&
-                    newState == BluetoothInputDevice.STATE_DISCONNECTED) {
+                if (oldState == BluetoothProfile.STATE_CONNECTED &&
+                    newState == BluetoothProfile.STATE_DISCONNECTED) {
                     sendMessage(DISCONNECT_HID_INCOMING);
                 }
-                if (newState == BluetoothInputDevice.STATE_CONNECTED ||
-                    newState == BluetoothInputDevice.STATE_DISCONNECTED) {
+                if (newState == BluetoothProfile.STATE_CONNECTED ||
+                    newState == BluetoothProfile.STATE_DISCONNECTED) {
                     sendMessage(TRANSITION_TO_STABLE);
                 }
             } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
@@ -194,7 +194,7 @@
         filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
         filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
         filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
-        filter.addAction(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED);
+        filter.addAction(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
         filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
 
         mContext.registerReceiver(mBroadcastReceiver, filter);
@@ -286,7 +286,7 @@
                         sendMessage(DISCONNECT_A2DP_OUTGOING);
                         deferMessage(message);
                         break;
-                    } else if (mService.getInputDeviceState(mDevice) !=
+                    } else if (mService.getInputDeviceConnectionState(mDevice) !=
                             BluetoothInputDevice.STATE_DISCONNECTED) {
                         sendMessage(DISCONNECT_HID_OUTGOING);
                         deferMessage(message);
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index a70de59..df212a8 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,91 +27,88 @@
 import java.util.ArrayList;
 import java.util.List;
 
+
 /**
- * Public API for controlling the Bluetooth HID (Input Device) Profile
+ * This class provides the public APIs to control the Bluetooth Input
+ * Device Profile.
  *
- * BluetoothInputDevice is a proxy object used to make calls to Bluetooth Service
- * which handles the HID profile.
+ *<p>BluetoothInputDevice is a proxy object for controlling the Bluetooth
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothInputDevice proxy object.
  *
- * Creating a BluetoothInputDevice object will initiate a binding with the
- * Bluetooth service. Users of this object should call close() when they
- * are finished, so that this proxy object can unbind from the service.
- *
- * Currently the Bluetooth service runs in the system server and this
- * proxy object will be immediately bound to the service on construction.
- *
- *  @hide
+ *<p>Each method is protected with its appropriate permission.
+ *@hide
  */
-public final class BluetoothInputDevice {
+public final class BluetoothInputDevice implements BluetoothProfile {
     private static final String TAG = "BluetoothInputDevice";
     private static final boolean DBG = false;
 
-    /** int extra for ACTION_INPUT_DEVICE_STATE_CHANGED */
-    public static final String EXTRA_INPUT_DEVICE_STATE =
-        "android.bluetooth.inputdevice.extra.INPUT_DEVICE_STATE";
-    /** int extra for ACTION_INPUT_DEVICE_STATE_CHANGED */
-    public static final String EXTRA_PREVIOUS_INPUT_DEVICE_STATE =
-        "android.bluetooth.inputdevice.extra.PREVIOUS_INPUT_DEVICE_STATE";
-
-    /** Indicates the state of an input device has changed.
-     * This intent will always contain EXTRA_INPUT_DEVICE_STATE,
-     * EXTRA_PREVIOUS_INPUT_DEVICE_STATE and BluetoothDevice.EXTRA_DEVICE
-     * extras.
+    /**
+     * Intent used to broadcast the change in connection state of the Input
+     * Device profile.
+     *
+     * <p>This intent will have 3 extras:
+     * <ul>
+     *   <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+     *   <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+     * </ul>
+     *
+     * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+     * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+     * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+     * receive.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_INPUT_DEVICE_STATE_CHANGED =
-        "android.bluetooth.inputdevice.action.INPUT_DEVICE_STATE_CHANGED";
-
-    public static final int STATE_DISCONNECTED = 0;
-    public static final int STATE_CONNECTING   = 1;
-    public static final int STATE_CONNECTED    = 2;
-    public static final int STATE_DISCONNECTING = 3;
-
-    /**
-     * Auto connection, incoming and outgoing connection are allowed at this
-     * priority level.
-     */
-    public static final int PRIORITY_AUTO_CONNECT = 1000;
-    /**
-     * Incoming and outgoing connection are allowed at this priority level
-     */
-    public static final int PRIORITY_ON = 100;
-    /**
-     * Connections to the device are not allowed at this priority level.
-     */
-    public static final int PRIORITY_OFF = 0;
-    /**
-     * Default priority level when the device is unpaired.
-     */
-    public static final int PRIORITY_UNDEFINED = -1;
+    public static final String ACTION_CONNECTION_STATE_CHANGED =
+        "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
 
     /**
      * Return codes for the connect and disconnect Bluez / Dbus calls.
+     * @hide
      */
     public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000;
 
+    /**
+     * @hide
+     */
     public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001;
 
+    /**
+     * @hide
+     */
     public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002;
 
+    /**
+     * @hide
+     */
     public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003;
 
+    /**
+     * @hide
+     */
     public static final int INPUT_OPERATION_SUCCESS = 5004;
 
-    private final IBluetooth mService;
-    private final Context mContext;
+    private ServiceListener mServiceListener;
+    private BluetoothAdapter mAdapter;
+    private IBluetooth mService;
 
     /**
      * Create a BluetoothInputDevice proxy object for interacting with the local
-     * Bluetooth Service which handle the HID profile.
-     * @param c Context
+     * Bluetooth Service which handles the InputDevice profile
+     *
      */
-    public BluetoothInputDevice(Context c) {
-        mContext = c;
-
+    /*package*/ BluetoothInputDevice(Context mContext, ServiceListener l) {
         IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
+        mServiceListener = l;
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
         if (b != null) {
             mService = IBluetooth.Stub.asInterface(b);
+            if (mServiceListener != null) {
+                mServiceListener.onServiceConnected(BluetoothProfile.INPUT_DEVICE, this);
+            }
         } else {
             Log.w(TAG, "Bluetooth Service not available!");
 
@@ -121,130 +118,151 @@
         }
     }
 
-    /** Initiate a connection to an Input device.
-     *
-     *  This function returns false on error and true if the connection
-     *  attempt is being made.
-     *
-     *  Listen for INPUT_DEVICE_STATE_CHANGED_ACTION to find out when the
-     *  connection is completed.
-     *  @param device Remote BT device.
-     *  @return false on immediate error, true otherwise
-     *  @hide
+    /**
+     * {@inheritDoc}
+     * @hide
      */
-    public boolean connectInputDevice(BluetoothDevice device) {
-        if (DBG) log("connectInputDevice(" + device + ")");
-        try {
-            return mService.connectInputDevice(device);
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-            return false;
+    public boolean connect(BluetoothDevice device) {
+        if (DBG) log("connect(" + device + ")");
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
+            try {
+                return mService.connectInputDevice(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return false;
+            }
         }
-    }
-
-    /** Initiate disconnect from an Input Device.
-     *  This function return false on error and true if the disconnection
-     *  attempt is being made.
-     *
-     *  Listen for INPUT_DEVICE_STATE_CHANGED_ACTION to find out when
-     *  disconnect is completed.
-     *
-     *  @param device Remote BT device.
-     *  @return false on immediate error, true otherwise
-     *  @hide
-     */
-    public boolean disconnectInputDevice(BluetoothDevice device) {
-        if (DBG) log("disconnectInputDevice(" + device + ")");
-        try {
-            return mService.disconnectInputDevice(device);
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-            return false;
-        }
-    }
-
-    /** Check if a specified InputDevice is connected.
-     *
-     *  @param device Remote BT device.
-     *  @return True if connected , false otherwise and on error.
-     *  @hide
-     */
-    public boolean isInputDeviceConnected(BluetoothDevice device) {
-        if (DBG) log("isInputDeviceConnected(" + device + ")");
-        int state = getInputDeviceState(device);
-        if (state == STATE_CONNECTED) return true;
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
         return false;
     }
 
-    /** Check if any Input Device is connected.
-     *
-     * @return List of devices, empty List on error.
+    /**
+     * {@inheritDoc}
      * @hide
      */
-    public List<BluetoothDevice> getConnectedInputDevices() {
-        if (DBG) log("getConnectedInputDevices()");
-        try {
-            return mService.getConnectedInputDevices();
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-            return new ArrayList<BluetoothDevice>();
+    public boolean disconnect(BluetoothDevice device) {
+        if (DBG) log("disconnect(" + device + ")");
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
+            try {
+                return mService.disconnectInputDevice(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return false;
+            }
         }
-    }
-
-    /** Get the state of an Input Device.
-     *
-     *  @param device Remote BT device.
-     *  @return The current state of the Input Device
-     *  @hide
-     */
-    public int getInputDeviceState(BluetoothDevice device) {
-        if (DBG) log("getInputDeviceState(" + device + ")");
-        try {
-            return mService.getInputDeviceState(device);
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-            return STATE_DISCONNECTED;
-        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
     }
 
     /**
-     * Set priority of an input device.
-     *
-     * Priority is a non-negative integer. Priority can take the following
-     * values:
-     * {@link PRIORITY_ON}, {@link PRIORITY_OFF}, {@link PRIORITY_AUTO_CONNECT}
-     *
-     * @param device Paired device.
-     * @param priority Integer priority
-     * @return true if priority is set, false on error
+     * {@inheritDoc}
      */
-    public boolean setInputDevicePriority(BluetoothDevice device, int priority) {
-        if (DBG) log("setInputDevicePriority(" + device + ", " + priority + ")");
-        try {
-            return mService.setInputDevicePriority(device, priority);
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-            return false;
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (DBG) log("getConnectedDevices()");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getConnectedInputDevices();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
         }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
     }
 
     /**
-     * Get the priority associated with an Input Device.
-     *
-     * @param device Input Device
-     * @return non-negative priority, or negative error code on error.
+     * {@inheritDoc}
      */
-    public int getInputDevicePriority(BluetoothDevice device) {
-        if (DBG) log("getInputDevicePriority(" + device + ")");
-        try {
-            return mService.getInputDevicePriority(device);
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-            return PRIORITY_OFF;
+    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+        if (DBG) log("getDevicesMatchingStates()");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getInputDevicesMatchingConnectionStates(states);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
         }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getConnectionState(BluetoothDevice device) {
+        if (DBG) log("getState(" + device + ")");
+        if (mService != null && isEnabled()
+            && isValidDevice(device)) {
+            try {
+                return mService.getInputDeviceConnectionState(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return BluetoothProfile.STATE_DISCONNECTED;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    public boolean setPriority(BluetoothDevice device, int priority) {
+        if (DBG) log("setPriority(" + device + ", " + priority + ")");
+        if (mService != null && isEnabled()
+            && isValidDevice(device)) {
+            if (priority != BluetoothProfile.PRIORITY_OFF &&
+                priority != BluetoothProfile.PRIORITY_ON) {
+              return false;
+            }
+            try {
+                return mService.setInputDevicePriority(device, priority);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return false;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    public int getPriority(BluetoothDevice device) {
+        if (DBG) log("getPriority(" + device + ")");
+        if (mService != null && isEnabled()
+            && isValidDevice(device)) {
+            try {
+                return mService.getInputDevicePriority(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return BluetoothProfile.PRIORITY_OFF;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return BluetoothProfile.PRIORITY_OFF;
+    }
+
+    private boolean isEnabled() {
+       if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+       return false;
+    }
+
+    private boolean isValidDevice(BluetoothDevice device) {
+       if (device == null) return false;
+
+       if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+       return false;
     }
 
     private static void log(String msg) {
-        Log.d(TAG, msg);
+      Log.d(TAG, msg);
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 1f07349..9ffed26 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -27,187 +27,261 @@
 import java.util.ArrayList;
 import java.util.List;
 
+
 /**
- * @hide
+ * This class provides the APIs to control the Bluetooth Pan
+ * Profile.
+ *
+ *<p>BluetoothPan is a proxy object for controlling the Bluetooth
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothPan proxy object.
+ *
+ *<p>Each method is protected with its appropriate permission.
+ *@hide
  */
-public final class BluetoothPan {
+public final class BluetoothPan implements BluetoothProfile {
     private static final String TAG = "BluetoothPan";
     private static final boolean DBG = false;
 
-    //TODO: This needs to inherit from BluetoothProfile like other profiles.
+    /**
+     * Intent used to broadcast the change in connection state of the Pan
+     * profile.
+     *
+     * <p>This intent will have 4 extras:
+     * <ul>
+     *   <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+     *   <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+     *   <li> {@link #EXTRA_LOCAL_ROLE} - Which local role the remote device is
+     *   bound to. </li>
+     * </ul>
+     *
+     * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+     * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+     * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+     *
+     * <p> {@link #EXTRA_LOCAL_ROLE} can be one of {@link #LOCAL_NAP_ROLE} or
+     * {@link #LOCAL_PANU_ROLE}
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+     * receive.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_CONNECTION_STATE_CHANGED =
+        "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
 
-    /** int extra for ACTION_PAN_STATE_CHANGED */
-    public static final String EXTRA_PAN_STATE = "android.bluetooth.pan.extra.STATE";
-
-    /** int extra for ACTION_PAN_STATE_CHANGED */
-    public static final String EXTRA_PREVIOUS_PAN_STATE =
-        "android.bluetooth.pan.extra.PREVIOUS_STATE";
-
-    /** int extra for ACTION_PAN_STATE_CHANGED */
+    /**
+     * Extra for {@link #ACTION_CONNECTION_STATE_CHANGED} intent
+     * The local role of the PAN profile that the remote device is bound to.
+     * It can be one of {@link #LOCAL_NAP_ROLE} or {@link #LOCAL_PANU_ROLE}.
+     */
     public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
 
+    /**
+     * The local device is acting as a Network Access Point.
+     */
     public static final int LOCAL_NAP_ROLE = 1;
+
+    /**
+     * The local device is acting as a PAN User.
+     */
     public static final int LOCAL_PANU_ROLE = 2;
 
     /**
-     * Indicates the state of an PAN device has changed.
-     * This intent will always contain EXTRA_DEVICE_STATE,
-     * EXTRA_PREVIOUS_DEVICE_STATE, BluetoothDevice.EXTRA_DEVICE
-     * and EXTRA_LOCAL_ROLE.
-     * extras.
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_PAN_STATE_CHANGED =
-      "android.bluetooth.pan.action.STATE_CHANGED";
-
-    public static final String NAP_ROLE = "nap";
-    public static final String NAP_BRIDGE = "pan1";
-
-    public static final int MAX_CONNECTIONS = 7;
-
-    public static final int STATE_DISCONNECTED = 0;
-    public static final int STATE_CONNECTING   = 1;
-    public static final int STATE_CONNECTED    = 2;
-    public static final int STATE_DISCONNECTING = 3;
-
-    /**
      * Return codes for the connect and disconnect Bluez / Dbus calls.
+     * @hide
      */
     public static final int PAN_DISCONNECT_FAILED_NOT_CONNECTED = 1000;
 
+    /**
+     * @hide
+     */
     public static final int PAN_CONNECT_FAILED_ALREADY_CONNECTED = 1001;
 
+    /**
+     * @hide
+     */
     public static final int PAN_CONNECT_FAILED_ATTEMPT_FAILED = 1002;
 
+    /**
+     * @hide
+     */
     public static final int PAN_OPERATION_GENERIC_FAILURE = 1003;
 
+    /**
+     * @hide
+     */
     public static final int PAN_OPERATION_SUCCESS = 1004;
 
-    private final IBluetooth mService;
-    private final Context mContext;
+    private ServiceListener mServiceListener;
+    private BluetoothAdapter mAdapter;
+    private IBluetooth mService;
 
     /**
      * Create a BluetoothPan proxy object for interacting with the local
-     * Bluetooth Pan service.
-     * @param c Context
+     * Bluetooth Service which handles the Pan profile
+     *
      */
-    public BluetoothPan(Context c) {
-        mContext = c;
-
+    /*package*/ BluetoothPan(Context mContext, ServiceListener l) {
         IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
+        mServiceListener = l;
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
         if (b != null) {
             mService = IBluetooth.Stub.asInterface(b);
+            if (mServiceListener != null) {
+                mServiceListener.onServiceConnected(BluetoothProfile.PAN, this);
+            }
         } else {
             Log.w(TAG, "Bluetooth Service not available!");
 
             // Instead of throwing an exception which prevents people from going
-            // into Wireless settings in the emulator. Let it crash later
-            // when it is actually used.
+            // into Wireless settings in the emulator. Let it crash later when it is actually used.
             mService = null;
         }
     }
 
     /**
-     * Initiate a PAN connection.
-     *
-     * This function returns false on error and true if the connection
-     * attempt is being made.
-     *
-     * Listen for {@link #ACTION_PAN_STATE_CHANGED} to find out when the
-     * connection is completed.
-     *
-     * @param device Remote BT device.
-     * @return false on immediate error, true otherwise
+     * {@inheritDoc}
      * @hide
      */
     public boolean connect(BluetoothDevice device) {
         if (DBG) log("connect(" + device + ")");
-        try {
-            return mService.connectPanDevice(device);
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-            return false;
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
+            try {
+                return mService.connectPanDevice(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return false;
+            }
         }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
     }
 
     /**
-     * Initiate disconnect from PAN.
-     *
-     * This function return false on error and true if the disconnection
-     * attempt is being made.
-     *
-     * Listen for {@link #ACTION_PAN_STATE_CHANGED} to find out when
-     * disconnect is completed.
-     *
-     * @param device Remote BT device.
-     * @return false on immediate error, true otherwise
+     * {@inheritDoc}
      * @hide
      */
     public boolean disconnect(BluetoothDevice device) {
         if (DBG) log("disconnect(" + device + ")");
-        try {
-            return mService.disconnectPanDevice(device);
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-            return false;
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
+            try {
+                return mService.disconnectPanDevice(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return false;
+            }
         }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
     }
 
     /**
-     * Get the state of a PAN Device.
-     *
-     * This function returns an int representing the state of the PAN connection
-     *
-     *  @param device Remote BT device.
-     *  @return The current state of the PAN Device
-     *  @hide
-     */
-    public int getPanDeviceState(BluetoothDevice device) {
-        if (DBG) log("getPanDeviceState(" + device + ")");
-        try {
-            return mService.getPanDeviceState(device);
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-            return STATE_DISCONNECTED;
-        }
-    }
-
-    /**
-     * Returns a set of all the connected PAN Devices
-     *
-     * Does not include devices that are currently connecting or disconnecting
-     *
-     *  @return List of PAN devices or empty on Error
-     * @hide
+     * {@inheritDoc}
      */
     public List<BluetoothDevice> getConnectedDevices() {
-       if (DBG) log("getConnectedDevices");
-       try {
-           return mService.getConnectedPanDevices();
-       } catch (RemoteException e) {
-           Log.e(TAG, "", e);
-           return new ArrayList<BluetoothDevice>();
-       }
+        if (DBG) log("getConnectedDevices()");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getConnectedPanDevices();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
     }
 
-    private static void log(String msg) {
-        Log.d(TAG, msg);
+    /**
+     * {@inheritDoc}
+     */
+    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+        if (DBG) log("getDevicesMatchingStates()");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getPanDevicesMatchingConnectionStates(states);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getConnectionState(BluetoothDevice device) {
+        if (DBG) log("getState(" + device + ")");
+        if (mService != null && isEnabled()
+            && isValidDevice(device)) {
+            try {
+                return mService.getPanDeviceConnectionState(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return BluetoothProfile.STATE_DISCONNECTED;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    public boolean setPriority(BluetoothDevice device, int priority) {
+        // Priorities are not supported for PAN devices - since we don't
+        // auto connect.
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @hide
+     */
+    public int getPriority(BluetoothDevice device) {
+        if (DBG) log("getPriority(" + device + ")");
+        // Priorities are not supported for PAN devices - since we don't
+        // auto connect.
+        return BluetoothProfile.PRIORITY_ON;
     }
 
     public void setBluetoothTethering(boolean value) {
+        if (DBG) log("setBluetoothTethering(" + value + ")");
         try {
             mService.setBluetoothTethering(value);
         } catch (RemoteException e) {
-            Log.e(TAG, "", e);
+            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
         }
     }
 
     public boolean isTetheringOn() {
+        if (DBG) log("isTetheringOn()");
         try {
             return mService.isTetheringOn();
         } catch (RemoteException e) {
-            Log.e(TAG, "", e);
+            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
             return false;
         }
     }
-}
+
+    private boolean isEnabled() {
+       if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+       return false;
+    }
+
+    private boolean isValidDevice(BluetoothDevice device) {
+       if (device == null) return false;
+
+       if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+       return false;
+    }
+
+    private static void log(String msg) {
+      Log.d(TAG, msg);
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index ef80195..1ad66f7 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -58,12 +58,25 @@
      * Headset and Handsfree profile
      */
     public static final int HEADSET = 1;
+
     /**
      * A2DP profile.
      */
     public static final int A2DP = 2;
 
     /**
+     * Input Device Profile
+     * @hide
+     */
+    public static final int INPUT_DEVICE = 3;
+
+    /**
+     * PAN Profile
+     * @hide
+     */
+    public static final int PAN = 4;
+
+    /**
      * Default priority for devices that we try to auto-connect to and
      * and allow incoming connections for the profile
      * @hide
diff --git a/core/java/android/bluetooth/BluetoothProfileState.java b/core/java/android/bluetooth/BluetoothProfileState.java
index 3f36926..18060a0 100644
--- a/core/java/android/bluetooth/BluetoothProfileState.java
+++ b/core/java/android/bluetooth/BluetoothProfileState.java
@@ -72,10 +72,10 @@
                     newState == BluetoothProfile.STATE_DISCONNECTED)) {
                     sendMessage(TRANSITION_TO_STABLE);
                 }
-            } else if (action.equals(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED)) {
-                int newState = intent.getIntExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, 0);
-                if (mProfile == HID && (newState == BluetoothInputDevice.STATE_CONNECTED ||
-                    newState == BluetoothInputDevice.STATE_DISCONNECTED)) {
+            } else if (action.equals(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED)) {
+                int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
+                if (mProfile == HID && (newState == BluetoothProfile.STATE_CONNECTED ||
+                    newState == BluetoothProfile.STATE_DISCONNECTED)) {
                     sendMessage(TRANSITION_TO_STABLE);
                 }
             } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
@@ -96,7 +96,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
         filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
-        filter.addAction(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED);
+        filter.addAction(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
         filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
         context.registerReceiver(mBroadcastReceiver, filter);
     }
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index aa1adcb..c08f14f 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -96,17 +96,32 @@
     public void startMonitoring(Context context, Handler target) {
         mContext = context;
         mCsHandler = target;
-        mBluetoothPan = new BluetoothPan(mContext);
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null) {
+            adapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.PAN);
+        }
     }
 
+    private BluetoothProfile.ServiceListener mProfileServiceListener =
+        new BluetoothProfile.ServiceListener() {
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            mBluetoothPan = (BluetoothPan) proxy;
+        }
+        public void onServiceDisconnected(int profile) {
+            mBluetoothPan = null;
+        }
+    };
+
     /**
      * Disable connectivity to a network
      * TODO: do away with return value after making MobileDataStateTracker async
      */
     public boolean teardown() {
         mTeardownRequested.set(true);
-        for (BluetoothDevice device: mBluetoothPan.getConnectedDevices()) {
-            mBluetoothPan.disconnect(device);
+        if (mBluetoothPan != null) {
+            for (BluetoothDevice device: mBluetoothPan.getConnectedDevices()) {
+                mBluetoothPan.disconnect(device);
+            }
         }
         return true;
     }
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index f3e73cf..d25f5d0 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -85,14 +85,16 @@
     boolean connectInputDevice(in BluetoothDevice device);
     boolean disconnectInputDevice(in BluetoothDevice device);
     List<BluetoothDevice> getConnectedInputDevices();
-    int getInputDeviceState(in BluetoothDevice device);
+    List<BluetoothDevice> getInputDevicesMatchingConnectionStates(in int[] states);
+    int getInputDeviceConnectionState(in BluetoothDevice device);
     boolean setInputDevicePriority(in BluetoothDevice device, int priority);
     int getInputDevicePriority(in BluetoothDevice device);
 
     boolean isTetheringOn();
     void setBluetoothTethering(boolean value);
-    int getPanDeviceState(in BluetoothDevice device);
+    int getPanDeviceConnectionState(in BluetoothDevice device);
     List<BluetoothDevice> getConnectedPanDevices();
+    List<BluetoothDevice> getPanDevicesMatchingConnectionStates(in int[] states);
     boolean connectPanDevice(in BluetoothDevice device);
     boolean disconnectPanDevice(in BluetoothDevice device);
 
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 85f64d0..81eb09c 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -115,7 +115,7 @@
     private CompatibilityInfo mCompatibilityInfo;
     private Display mDefaultDisplay;
 
-    private static final LongSparseArray<Object> EMPTY_ARRAY = new LongSparseArray<Object>() {
+    private static final LongSparseArray<Object> EMPTY_ARRAY = new LongSparseArray<Object>(0) {
         @Override
         public void put(long k, Object o) {
             throw new UnsupportedOperationException();
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index aabe872..958bf08 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -508,23 +508,86 @@
      * finish processing the data in them.
      *
      * <p>The size of the buffer is determined by multiplying the preview
-     * image width, height, and bytes per pixel.  The width and height can be
-     * read from {@link Camera.Parameters#getPreviewSize()}.  Bytes per pixel
+     * image width, height, and bytes per pixel. The width and height can be
+     * read from {@link Camera.Parameters#getPreviewSize()}. Bytes per pixel
      * can be computed from
      * {@link android.graphics.ImageFormat#getBitsPerPixel(int)} / 8,
      * using the image format from {@link Camera.Parameters#getPreviewFormat()}.
      *
      * <p>This method is only necessary when
-     * {@link #setPreviewCallbackWithBuffer(PreviewCallback)} is used.  When
+     * {@link #setPreviewCallbackWithBuffer(PreviewCallback)} is used. When
      * {@link #setPreviewCallback(PreviewCallback)} or
      * {@link #setOneShotPreviewCallback(PreviewCallback)} are used, buffers
-     * are automatically allocated.
+     * are automatically allocated. When a supplied buffer is too small to
+     * hold the preview frame data, preview callback will return null and
+     * the buffer will be removed from the buffer queue.
      *
      * @param callbackBuffer the buffer to add to the queue.
      *     The size should be width * height * bits_per_pixel / 8.
      * @see #setPreviewCallbackWithBuffer(PreviewCallback)
      */
-    public native final void addCallbackBuffer(byte[] callbackBuffer);
+    public final void addCallbackBuffer(byte[] callbackBuffer)
+    {
+        _addCallbackBuffer(callbackBuffer, CAMERA_MSG_PREVIEW_FRAME);
+    }
+
+    /**
+     * Adds a pre-allocated buffer to the raw image callback buffer queue.
+     * Applications can add one or more buffers to the queue. When a raw image
+     * frame arrives and there is still at least one available buffer, the
+     * buffer will be used to hold the raw image data and removed from the
+     * queue. Then raw image callback is invoked with the buffer. If a raw
+     * image frame arrives but there is no buffer left, the frame is
+     * discarded. Applications should add buffers back when they finish
+     * processing the data in them by calling this method again in order
+     * to avoid running out of raw image callback buffers.
+     *
+     * <p>The size of the buffer is determined by multiplying the raw image
+     * width, height, and bytes per pixel. The width and height can be
+     * read from {@link Camera.Parameters#getPictureSize()}. Bytes per pixel
+     * can be computed from
+     * {@link android.graphics.ImageFormat#getBitsPerPixel(int)} / 8,
+     * using the image format from {@link Camera.Parameters#getPreviewFormat()}.
+     *
+     * <p>This method is only necessary when the PictureCallbck for raw image
+     * is used while calling {@link #takePicture(Camera.ShutterCallback,
+     * Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)}.
+     *
+     * Please note that by calling this method, the mode for application-managed
+     * callback buffers is triggered. If this method has never been called,
+     * null will be returned by the raw image callback since there is
+     * no image callback buffer available. Furthermore, When a supplied buffer
+     * is too small to hold the raw image data, raw image callback will return
+     * null and the buffer will be removed from the buffer queue.
+     *
+     * @param callbackBuffer the buffer to add to the raw image callback buffer
+     *     queue. The size should be width * height * (bits per pixel) / 8. An
+     *     null callbackBuffer will be ignored and won't be added to the queue.
+     *
+     * @see #takePicture(Camera.ShutterCallback,
+     * Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)}.
+     *
+     * {@hide}
+     */
+    public final void addRawImageCallbackBuffer(byte[] callbackBuffer)
+    {
+        addCallbackBuffer(callbackBuffer, CAMERA_MSG_RAW_IMAGE);
+    }
+
+    private final void addCallbackBuffer(byte[] callbackBuffer, int msgType)
+    {
+        // CAMERA_MSG_VIDEO_FRAME may be allowed in the future.
+        if (msgType != CAMERA_MSG_PREVIEW_FRAME &&
+            msgType != CAMERA_MSG_RAW_IMAGE) {
+            throw new IllegalArgumentException(
+                            "Unsupported message type: " + msgType);
+        }
+
+        _addCallbackBuffer(callbackBuffer, msgType);
+    }
+
+    private native final void _addCallbackBuffer(
+                                byte[] callbackBuffer, int msgType);
 
     private class EventHandler extends Handler
     {
@@ -735,7 +798,7 @@
             PictureCallback jpeg) {
         takePicture(shutter, raw, null, jpeg);
     }
-    private native final void native_takePicture();
+    private native final void native_takePicture(int msgType);
 
     /**
      * Triggers an asynchronous image capture. The camera service will initiate
@@ -743,7 +806,8 @@
      * The shutter callback occurs after the image is captured. This can be used
      * to trigger a sound to let the user know that image has been captured. The
      * raw callback occurs when the raw image data is available (NOTE: the data
-     * may be null if the hardware does not have enough memory to make a copy).
+     * will be null if there is no raw image callback buffer available or the
+     * raw image callback buffer is not large enough to hold the raw image).
      * The postview callback occurs when a scaled, fully processed postview
      * image is available (NOTE: not all hardware supports this). The jpeg
      * callback occurs when the compressed image is available. If the
@@ -762,6 +826,8 @@
      * @param raw       the callback for raw (uncompressed) image data, or null
      * @param postview  callback with postview image data, may be null
      * @param jpeg      the callback for JPEG image data, or null
+     *
+     * @see #addRawImageCallbackBuffer(byte[])
      */
     public final void takePicture(ShutterCallback shutter, PictureCallback raw,
             PictureCallback postview, PictureCallback jpeg) {
@@ -769,7 +835,23 @@
         mRawImageCallback = raw;
         mPostviewCallback = postview;
         mJpegCallback = jpeg;
-        native_takePicture();
+
+        // If callback is not set, do not send me callbacks.
+        int msgType = 0;
+        if (mShutterCallback != null) {
+            msgType |= CAMERA_MSG_SHUTTER;
+        }
+        if (mRawImageCallback != null) {
+            msgType |= CAMERA_MSG_RAW_IMAGE;
+        }
+        if (mPostviewCallback != null) {
+            msgType |= CAMERA_MSG_POSTVIEW_FRAME;
+        }
+        if (mJpegCallback != null) {
+            msgType |= CAMERA_MSG_COMPRESSED_IMAGE;
+        }
+
+        native_takePicture(msgType);
     }
 
     /**
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 8c55bf3..78d7991 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -122,13 +122,13 @@
      *
      *          final float alpha = 0.8;
      *
-     *          gravity[0] = alpha * gravity[0] + (1 - alpha) * event.data[0];
-     *          gravity[1] = alpha * gravity[1] + (1 - alpha) * event.data[1];
-     *          gravity[2] = alpha * gravity[2] + (1 - alpha) * event.data[2];
+     *          gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
+     *          gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
+     *          gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];
      *
-     *          linear_acceleration[0] = event.data[0] - gravity[0];
-     *          linear_acceleration[1] = event.data[1] - gravity[1];
-     *          linear_acceleration[2] = event.data[2] - gravity[2];
+     *          linear_acceleration[0] = event.values[0] - gravity[0];
+     *          linear_acceleration[1] = event.values[1] - gravity[1];
+     *          linear_acceleration[2] = event.values[2] - gravity[2];
      *     }
      * </pre>
      *
@@ -186,9 +186,9 @@
      *     {
      *          if (timestamp != 0) {
      *              final float dT = (event.timestamp - timestamp) * NS2S;
-     *              angle[0] += event.data[0] * dT;
-     *              angle[1] += event.data[1] * dT;
-     *              angle[2] += event.data[2] * dT;
+     *              angle[0] += event.values[0] * dT;
+     *              angle[1] += event.values[1] * dT;
+     *              angle[2] += event.values[2] * dT;
      *          }
      *          timestamp = event.timestamp;
      *     }
diff --git a/core/java/android/pim/ICalendar.java b/core/java/android/pim/ICalendar.java
index cc0f45e..9c4eaf4 100644
--- a/core/java/android/pim/ICalendar.java
+++ b/core/java/android/pim/ICalendar.java
@@ -578,6 +578,23 @@
                             + text);
                 }
                 parameter.name = text.substring(startIndex + 1, equalIndex);
+            } else if (c == '"') {
+                if (parameter == null) {
+                    throw new FormatException("Expected parameter before '\"' in " + text);
+                }
+                if (equalIndex == -1) {
+                    throw new FormatException("Expected '=' within parameter in " + text);
+                }
+                if (state.index > equalIndex + 1) {
+                    throw new FormatException("Parameter value cannot contain a '\"' in " + text);
+                }
+                final int endQuote = text.indexOf('"', state.index + 1);
+                if (endQuote < 0) {
+                    throw new FormatException("Expected closing '\"' in " + text);
+                }
+                parameter.value = text.substring(state.index + 1, endQuote);
+                state.index = endQuote + 1;
+                return parameter;
             }
             ++state.index;
         }
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 3bfd005..57ee440 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -139,8 +139,6 @@
     public static final int SEARCHES_PROJECTION_SEARCH_INDEX = 1;
     public static final int SEARCHES_PROJECTION_DATE_INDEX = 2;
 
-    private static final String SEARCHES_WHERE_CLAUSE = "search = ?";
-
     /* Set a cap on the count of history items in the history/bookmark
        table, to prevent db and layout operations from dragging to a
        crawl.  Revisit this cap when/if db/layout performance
@@ -167,6 +165,13 @@
     }
 
     /**
+     * Passed along with an Intent to a browser, specifying that a new tab
+     * be created.  Overrides EXTRA_APPLICATION_ID; if both are set, a new tab
+     * will be used, rather than using the same one.
+     */
+    public static final String EXTRA_CREATE_NEW_TAB = "create_new_tab";
+
+    /**
      * Stores a Bitmap extra in an {@link Intent} representing the screenshot of
      * a page to share.  When receiving an {@link Intent#ACTION_SEND} from the
      * Browser, use this to access the screenshot.
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index b05b078..4f88612 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -862,8 +862,9 @@
     }
 
     /**
-     * Types of data used to produce the display name for a contact. Listed in the order
-     * of increasing priority.
+     * Types of data used to produce the display name for a contact. In the order
+     * of increasing priority: {@link #EMAIL}, {@link #PHONE},
+     * {@link #ORGANIZATION}, {@link #NICKNAME}, {@link #STRUCTURED_NAME}.
      */
     public interface DisplayNameSources {
         public static final int UNDEFINED = 0;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f5cf76e..1718189 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1797,7 +1797,6 @@
          */
         public static final String[] SETTINGS_TO_BACKUP = {
             STAY_ON_WHILE_PLUGGED_IN,
-            WIFI_SLEEP_POLICY,
             WIFI_USE_STATIC_IP,
             WIFI_STATIC_IP,
             WIFI_STATIC_GATEWAY,
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 3316ea5..578580a 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -57,6 +57,7 @@
     private final BluetoothService mBluetoothService;
     private final BluetoothAdapter mAdapter;
     private BluetoothA2dp mA2dp;
+    private BluetoothInputDevice mInputDevice;
     private final Context mContext;
     // The WakeLock is used for bringing up the LCD during a pairing request
     // from remote device when Android is in Suspend state.
@@ -125,15 +126,24 @@
 
     /*package*/ void getProfileProxy() {
         mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.A2DP);
+        mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.INPUT_DEVICE);
     }
 
     private BluetoothProfile.ServiceListener mProfileServiceListener =
         new BluetoothProfile.ServiceListener() {
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            mA2dp = (BluetoothA2dp) proxy;
+            if (profile == BluetoothProfile.A2DP) {
+                mA2dp = (BluetoothA2dp) proxy;
+            } else if (profile == BluetoothProfile.INPUT_DEVICE) {
+                mInputDevice = (BluetoothInputDevice) proxy;
+            }
         }
         public void onServiceDisconnected(int profile) {
-            mA2dp = null;
+            if (profile == BluetoothProfile.A2DP) {
+                mA2dp = null;
+            } else if (profile == BluetoothProfile.INPUT_DEVICE) {
+                mInputDevice = null;
+            }
         }
     };
 
@@ -651,10 +661,9 @@
             } else {
                 Log.i(TAG, "Rejecting incoming A2DP / AVRCP connection from " + address);
             }
-        } else if (BluetoothUuid.isInputDevice(uuid) && !isOtherInputDeviceConnected(address)) {
-            BluetoothInputDevice inputDevice = new BluetoothInputDevice(mContext);
-            authorized = inputDevice.getInputDevicePriority(device) >
-                         BluetoothInputDevice.PRIORITY_OFF;
+        } else if (mInputDevice != null && BluetoothUuid.isInputDevice(uuid)) {
+            // We can have more than 1 input device connected.
+            authorized = mInputDevice.getPriority(device) > BluetoothInputDevice.PRIORITY_OFF;
              if (authorized) {
                  Log.i(TAG, "Allowing incoming HID connection from " + address);
              } else {
@@ -669,18 +678,6 @@
         return authorized;
     }
 
-    private boolean isOtherInputDeviceConnected(String address) {
-        List<BluetoothDevice> devices =
-            mBluetoothService.lookupInputDevicesMatchingStates(new int[] {
-                                                BluetoothInputDevice.STATE_CONNECTING,
-                                                BluetoothInputDevice.STATE_CONNECTED});
-
-        for (BluetoothDevice device : devices) {
-            if (!device.getAddress().equals(address)) return true;
-        }
-        return false;
-    }
-
     private boolean onAgentOutOfBandDataAvailable(String objectPath) {
         if (!mBluetoothService.isEnabled()) return false;
 
@@ -758,7 +755,7 @@
 
             boolean connected = false;
             BluetoothDevice device = mAdapter.getRemoteDevice(address);
-            int state = mBluetoothService.getInputDeviceState(device);
+            int state = mBluetoothService.getInputDeviceConnectionState(device);
             if (state == BluetoothInputDevice.STATE_CONNECTING) {
                 if (result == BluetoothInputDevice.INPUT_CONNECT_FAILED_ALREADY_CONNECTED) {
                     connected = true;
@@ -788,7 +785,7 @@
 
             boolean connected = false;
             BluetoothDevice device = mAdapter.getRemoteDevice(address);
-            int state = mBluetoothService.getPanDeviceState(device);
+            int state = mBluetoothService.getPanDeviceConnectionState(device);
             if (state == BluetoothPan.STATE_CONNECTING) {
                 if (result == BluetoothPan.PAN_CONNECT_FAILED_ALREADY_CONNECTED) {
                     connected = true;
diff --git a/core/java/android/server/BluetoothInputProfileHandler.java b/core/java/android/server/BluetoothInputProfileHandler.java
index 7ffa5ae..cdc0f2d 100644
--- a/core/java/android/server/BluetoothInputProfileHandler.java
+++ b/core/java/android/server/BluetoothInputProfileHandler.java
@@ -64,7 +64,7 @@
                                             BluetoothDeviceProfileState state) {
         String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
         if (objectPath == null ||
-            getInputDeviceState(device) != BluetoothInputDevice.STATE_DISCONNECTED ||
+            getInputDeviceConnectionState(device) != BluetoothInputDevice.STATE_DISCONNECTED ||
             getInputDevicePriority(device) == BluetoothInputDevice.PRIORITY_OFF) {
             return false;
         }
@@ -92,7 +92,7 @@
                                                BluetoothDeviceProfileState state) {
         String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
         if (objectPath == null ||
-                getInputDeviceState(device) == BluetoothInputDevice.STATE_DISCONNECTED) {
+                getInputDeviceConnectionState(device) == BluetoothInputDevice.STATE_DISCONNECTED) {
             return false;
         }
         if (state != null) {
@@ -115,7 +115,7 @@
         return true;
     }
 
-    synchronized int getInputDeviceState(BluetoothDevice device) {
+    synchronized int getInputDeviceConnectionState(BluetoothDevice device) {
         if (mInputDevices.get(device) == null) {
             return BluetoothInputDevice.STATE_DISCONNECTED;
         }
@@ -128,6 +128,11 @@
         return devices;
     }
 
+    synchronized List<BluetoothDevice> getInputDevicesMatchingConnectionStates(int[] states) {
+        List<BluetoothDevice> devices = lookupInputDevicesMatchingStates(states);
+        return devices;
+    }
+
     synchronized int getInputDevicePriority(BluetoothDevice device) {
         return Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.getBluetoothInputDevicePriorityKey(device.getAddress()),
@@ -147,7 +152,7 @@
         List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>();
 
         for (BluetoothDevice device: mInputDevices.keySet()) {
-            int inputDeviceState = getInputDeviceState(device);
+            int inputDeviceState = getInputDeviceConnectionState(device);
             for (int state : states) {
                 if (state == inputDeviceState) {
                     inputDevices.add(device);
@@ -178,10 +183,10 @@
             setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_AUTO_CONNECT);
         }
 
-        Intent intent = new Intent(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED);
+        Intent intent = new Intent(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
-        intent.putExtra(BluetoothInputDevice.EXTRA_PREVIOUS_INPUT_DEVICE_STATE, prevState);
-        intent.putExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, state);
+        intent.putExtra(BluetoothInputDevice.EXTRA_PREVIOUS_STATE, prevState);
+        intent.putExtra(BluetoothInputDevice.EXTRA_STATE, state);
         mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM);
 
         debugLog("InputDevice state : device: " + device + " State:" + prevState + "->" + state);
diff --git a/core/java/android/server/BluetoothPanProfileHandler.java b/core/java/android/server/BluetoothPanProfileHandler.java
index fb96439..3f24811 100644
--- a/core/java/android/server/BluetoothPanProfileHandler.java
+++ b/core/java/android/server/BluetoothPanProfileHandler.java
@@ -58,6 +58,9 @@
     private Context mContext;
     private BluetoothService mBluetoothService;
 
+    static final String NAP_ROLE = "nap";
+    static final String NAP_BRIDGE = "pan1";
+
     private BluetoothPanProfileHandler(Context context, BluetoothService service) {
         mContext = context;
         mPanDevices = new HashMap<BluetoothDevice, BluetoothPanDevice>();
@@ -114,7 +117,7 @@
         }
     }
 
-    synchronized int getPanDeviceState(BluetoothDevice device) {
+    synchronized int getPanDeviceConnectionState(BluetoothDevice device) {
         BluetoothPanDevice panDevice = mPanDevices.get(device);
         if (panDevice == null) {
             return BluetoothPan.STATE_DISCONNECTED;
@@ -125,13 +128,13 @@
     synchronized boolean connectPanDevice(BluetoothDevice device) {
         String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
         if (DBG) Log.d(TAG, "connect PAN(" + objectPath + ")");
-        if (getPanDeviceState(device) != BluetoothPan.STATE_DISCONNECTED) {
+        if (getPanDeviceConnectionState(device) != BluetoothPan.STATE_DISCONNECTED) {
             errorLog(device + " already connected to PAN");
         }
 
         int connectedCount = 0;
         for (BluetoothDevice panDevice: mPanDevices.keySet()) {
-            if (getPanDeviceState(panDevice) == BluetoothPan.STATE_CONNECTED) {
+            if (getPanDeviceConnectionState(panDevice) == BluetoothPan.STATE_CONNECTED) {
                 connectedCount ++;
             }
         }
@@ -187,18 +190,33 @@
         List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
 
         for (BluetoothDevice device: mPanDevices.keySet()) {
-            if (getPanDeviceState(device) == BluetoothPan.STATE_CONNECTED) {
+            if (getPanDeviceConnectionState(device) == BluetoothPan.STATE_CONNECTED) {
                 devices.add(device);
             }
         }
         return devices;
     }
 
+    synchronized List<BluetoothDevice> getPanDevicesMatchingConnectionStates(int[] states) {
+        List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
+
+        for (BluetoothDevice device: mPanDevices.keySet()) {
+            int panDeviceState = getPanDeviceConnectionState(device);
+            for (int state : states) {
+                if (state == panDeviceState) {
+                    devices.add(device);
+                    break;
+                }
+            }
+        }
+        return devices;
+    }
+
     synchronized boolean disconnectPanDevice(BluetoothDevice device) {
         String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
         debugLog("disconnect PAN(" + objectPath + ")");
 
-        int state = getPanDeviceState(device);
+        int state = getPanDeviceConnectionState(device);
         if (state != BluetoothPan.STATE_CONNECTED) {
             debugLog(device + " already disconnected from PAN");
             return false;
@@ -274,14 +292,10 @@
             panDevice.mLocalRole = role;
         }
 
-        if (state == BluetoothPan.STATE_DISCONNECTED) {
-            mPanDevices.remove(device);
-        }
-
-        Intent intent = new Intent(BluetoothPan.ACTION_PAN_STATE_CHANGED);
+        Intent intent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
-        intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_PAN_STATE, prevState);
-        intent.putExtra(BluetoothPan.EXTRA_PAN_STATE, state);
+        intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_STATE, prevState);
+        intent.putExtra(BluetoothPan.EXTRA_STATE, state);
         intent.putExtra(BluetoothPan.EXTRA_LOCAL_ROLE, role);
         mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM);
 
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index a295de5..ebe3ef2 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -31,6 +31,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothDeviceProfileState;
 import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothInputDevice;
 import android.bluetooth.BluetoothPan;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothProfileState;
@@ -83,6 +84,8 @@
     private int mNativeData;
     private BluetoothEventLoop mEventLoop;
     private BluetoothHeadset mBluetoothHeadset;
+    private BluetoothInputDevice mInputDevice;
+    private BluetoothPan mPan;
     private boolean mIsAirplaneSensitive;
     private boolean mIsAirplaneToggleable;
     private int mBluetoothState;
@@ -355,7 +358,8 @@
         setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF);
 
         if (mAdapterSdpHandles != null) removeReservedServiceRecordsNative(mAdapterSdpHandles);
-        setBluetoothTetheringNative(false, BluetoothPan.NAP_ROLE, BluetoothPan.NAP_BRIDGE);
+        setBluetoothTetheringNative(false, BluetoothPanProfileHandler.NAP_ROLE,
+                BluetoothPanProfileHandler.NAP_BRIDGE);
 
         // Allow 3 seconds for profiles to gracefully disconnect
         // TODO: Introduce a callback mechanism so that each profile can notify
@@ -604,7 +608,8 @@
         addReservedSdpRecords(uuids);
 
         // Enable profiles maintained by Bluez userspace.
-        setBluetoothTetheringNative(true, BluetoothPan.NAP_ROLE, BluetoothPan.NAP_BRIDGE);
+        setBluetoothTetheringNative(true, BluetoothPanProfileHandler.NAP_ROLE,
+                BluetoothPanProfileHandler.NAP_BRIDGE);
 
         // Add SDP records for profiles maintained by Bluez userspace
         uuids.add(BluetoothUuid.AudioSource);
@@ -2078,6 +2083,10 @@
 
         mAdapter.getProfileProxy(mContext,
                                  mBluetoothProfileServiceListener, BluetoothProfile.HEADSET);
+        mAdapter.getProfileProxy(mContext,
+                mBluetoothProfileServiceListener, BluetoothProfile.INPUT_DEVICE);
+        mAdapter.getProfileProxy(mContext,
+                mBluetoothProfileServiceListener, BluetoothProfile.PAN);
 
         pw.println("\n--Known devices--");
         for (String address : mDeviceProperties.keySet()) {
@@ -2119,16 +2128,26 @@
             }
         }
 
-        // Rather not do this from here, but no-where else and I need this
-        // dump
+        dumpHeadsetProfile(pw);
+        dumpInputDeviceProfile(pw);
+        dumpPanProfile(pw);
+
+        pw.println("\n--Application Service Records--");
+        for (Integer handle : mServiceRecordToPid.keySet()) {
+            Integer pid = mServiceRecordToPid.get(handle);
+            pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
+        }
+    }
+
+    private void dumpHeadsetProfile(PrintWriter pw) {
         pw.println("\n--Headset Service--");
         if (mBluetoothHeadset != null) {
             List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices();
             if (deviceList.size() == 0) {
-                pw.println("\n--No headsets connected--");
+                pw.println("No headsets connected");
             } else {
                 BluetoothDevice device = deviceList.get(0);
-                pw.println("\ngetConnectedDevices[0] = " + device);
+                pw.println("getConnectedDevices[0] = " + device);
 
                 switch (mBluetoothHeadset.getConnectionState(device)) {
                     case BluetoothHeadset.STATE_CONNECTING:
@@ -2151,31 +2170,106 @@
             deviceList.clear();
             deviceList = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] {
                      BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
-            pw.println("\n--Connected and Disconnected Headsets");
+            pw.println("--Connected and Disconnected Headsets");
             for (BluetoothDevice device: deviceList) {
                 pw.println(device);
                 if (mBluetoothHeadset.isAudioConnected(device)) {
                     pw.println("SCO audio connected to device:" + device);
                 }
             }
-
-            mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
         }
+        mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
+    }
 
-        pw.println("\n--Application Service Records--");
-        for (Integer handle : mServiceRecordToPid.keySet()) {
-            Integer pid = mServiceRecordToPid.get(handle);
-            pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
+    private void dumpInputDeviceProfile(PrintWriter pw) {
+        pw.println("\n--Bluetooth Service- Input Device Profile");
+        if (mInputDevice != null) {
+            List<BluetoothDevice> deviceList = mInputDevice.getConnectedDevices();
+            if (deviceList.size() == 0) {
+                pw.println("No input devices connected");
+            } else {
+                pw.println("Number of connected devices:" + deviceList.size());
+                BluetoothDevice device = deviceList.get(0);
+                pw.println("getConnectedDevices[0] = " + device);
+                pw.println("Priority of Connected device = " + mInputDevice.getPriority(device));
+
+                switch (mInputDevice.getConnectionState(device)) {
+                    case BluetoothInputDevice.STATE_CONNECTING:
+                        pw.println("getConnectionState() = STATE_CONNECTING");
+                        break;
+                    case BluetoothInputDevice.STATE_CONNECTED:
+                        pw.println("getConnectionState() = STATE_CONNECTED");
+                        break;
+                    case BluetoothInputDevice.STATE_DISCONNECTING:
+                        pw.println("getConnectionState() = STATE_DISCONNECTING");
+                        break;
+                }
+            }
+            deviceList.clear();
+            deviceList = mInputDevice.getDevicesMatchingConnectionStates(new int[] {
+                     BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
+            pw.println("--Connected and Disconnected input devices");
+            for (BluetoothDevice device: deviceList) {
+                pw.println(device);
+            }
         }
+        mAdapter.closeProfileProxy(BluetoothProfile.INPUT_DEVICE, mBluetoothHeadset);
+    }
+
+    private void dumpPanProfile(PrintWriter pw) {
+        pw.println("\n--Bluetooth Service- Pan Profile");
+        if (mPan != null) {
+            List<BluetoothDevice> deviceList = mPan.getConnectedDevices();
+            if (deviceList.size() == 0) {
+                pw.println("No Pan devices connected");
+            } else {
+                pw.println("Number of connected devices:" + deviceList.size());
+                BluetoothDevice device = deviceList.get(0);
+                pw.println("getConnectedDevices[0] = " + device);
+                pw.println("Priority of Connected device = " + mPan.getPriority(device));
+
+                switch (mPan.getConnectionState(device)) {
+                    case BluetoothInputDevice.STATE_CONNECTING:
+                        pw.println("getConnectionState() = STATE_CONNECTING");
+                        break;
+                    case BluetoothInputDevice.STATE_CONNECTED:
+                        pw.println("getConnectionState() = STATE_CONNECTED");
+                        break;
+                    case BluetoothInputDevice.STATE_DISCONNECTING:
+                        pw.println("getConnectionState() = STATE_DISCONNECTING");
+                        break;
+                }
+            }
+            deviceList.clear();
+            deviceList = mPan.getDevicesMatchingConnectionStates(new int[] {
+                     BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
+            pw.println("--Connected and Disconnected Pan devices");
+            for (BluetoothDevice device: deviceList) {
+                pw.println(device);
+            }
+        }
+        mAdapter.closeProfileProxy(BluetoothProfile.PAN, mBluetoothHeadset);
     }
 
     private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
         new BluetoothProfile.ServiceListener() {
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            mBluetoothHeadset = (BluetoothHeadset) proxy;
-    }
+            if (profile == BluetoothProfile.HEADSET) {
+                mBluetoothHeadset = (BluetoothHeadset) proxy;
+            } else if (profile == BluetoothProfile.INPUT_DEVICE) {
+                mInputDevice = (BluetoothInputDevice) proxy;
+            } else if (profile == BluetoothProfile.PAN) {
+                mPan = (BluetoothPan) proxy;
+            }
+        }
         public void onServiceDisconnected(int profile) {
-            mBluetoothHeadset = null;
+            if (profile == BluetoothProfile.HEADSET) {
+                mBluetoothHeadset = null;
+            } else if (profile == BluetoothProfile.INPUT_DEVICE) {
+                mInputDevice = null;
+            } else if (profile == BluetoothProfile.PAN) {
+                mPan = null;
+            }
         }
     };
 
@@ -2253,9 +2347,9 @@
         mBluetoothPanProfileHandler.setBluetoothTethering(value);
     }
 
-    public synchronized int getPanDeviceState(BluetoothDevice device) {
+    public synchronized int getPanDeviceConnectionState(BluetoothDevice device) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        return mBluetoothPanProfileHandler.getPanDeviceState(device);
+        return mBluetoothPanProfileHandler.getPanDeviceConnectionState(device);
     }
 
     public synchronized boolean connectPanDevice(BluetoothDevice device) {
@@ -2269,6 +2363,12 @@
         return mBluetoothPanProfileHandler.getConnectedPanDevices();
     }
 
+    public synchronized List<BluetoothDevice> getPanDevicesMatchingConnectionStates(
+            int[] states) {
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+        return mBluetoothPanProfileHandler.getPanDevicesMatchingConnectionStates(states);
+    }
+
     public synchronized boolean disconnectPanDevice(BluetoothDevice device) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
             "Need BLUETOOTH_ADMIN permission");
@@ -2311,9 +2411,9 @@
         return mBluetoothInputProfileHandler.disconnectInputDeviceInternal(device);
     }
 
-    public synchronized int getInputDeviceState(BluetoothDevice device) {
+    public synchronized int getInputDeviceConnectionState(BluetoothDevice device) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        return mBluetoothInputProfileHandler.getInputDeviceState(device);
+        return mBluetoothInputProfileHandler.getInputDeviceConnectionState(device);
 
     }
 
@@ -2322,6 +2422,13 @@
         return mBluetoothInputProfileHandler.getConnectedInputDevices();
     }
 
+    public synchronized List<BluetoothDevice> getInputDevicesMatchingConnectionStates(
+            int[] states) {
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+        return mBluetoothInputProfileHandler.getInputDevicesMatchingConnectionStates(states);
+    }
+
+
     public synchronized int getInputDevicePriority(BluetoothDevice device) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         return mBluetoothInputProfileHandler.getInputDevicePriority(device);
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 97a216a..1e4cca9 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1727,6 +1727,17 @@
         }
     }
 
+    /**
+     * Inform this layout that not all of its lines will be displayed, because a maximum number of
+     * lines has been set on the associated TextView.
+     *
+     * A non strictly positive value means that all lines are displayed.
+     *
+     * @param lineCount number of visible lines
+     * @hide
+     */
+    public void setMaximumVisibleLineCount(int lineCount) {}
+
     private CharSequence mText;
     private TextPaint mPaint;
     /* package */ TextPaint mWorkPaint;
@@ -1765,14 +1776,4 @@
     /* package */ static final Directions DIRS_ALL_RIGHT_TO_LEFT =
         new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG });
 
-    /**
-     * Inform this layout that not all of its lines will be displayed, because a maximum number of
-     * lines has been set on the associated TextView.
-     *
-     * A non positive value means that all lines are displayed.
-     *
-     * @param line line number of the last visible line (line numbers start at 1 for the first line)
-     * @hide
-     */
-    public void setMaximumVisibleLineCount(int line) {}
 }
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index a4546f0..a826a97 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -355,8 +355,6 @@
                                 okBottom = fitBottom;
                         }
                     } else {
-                        if (ellipsize != null) {
-                            // Break only at spaces using ok indexes.
                             if (ok != here) {
                                 // Log.e("text", "output ok " + here + " to " +ok);
 
@@ -372,43 +370,7 @@
                                         chooseHtv, fm, hasTabOrEmoji,
                                         needMultiply, paraStart, chdirs, dir, easy,
                                         ok == bufEnd, includepad, trackpad,
-                                        chs, widths, here - paraStart,
-                                        ellipsize, ellipsizedWidth, okWidth,
-                                        paint);
-
-                                here = ok;
-                            } else {
-                                // Act like it fit even though it didn't.
-
-                                fitWidth = w;
-                                here = fit = j + 1;
-
-                                if (fmTop < fitTop)
-                                    fitTop = fmTop;
-                                if (fmAscent < fitAscent)
-                                    fitAscent = fmAscent;
-                                if (fmDescent > fitDescent)
-                                    fitDescent = fmDescent;
-                                if (fmBottom > fitBottom)
-                                    fitBottom = fmBottom;
-                            }
-                        } else {
-                            if (ok != here) {
-                                // Log.e("text", "output ok " + here + " to " +ok);
-
-                                while (ok < spanEnd && chs[ok - paraStart] == CHAR_SPACE) {
-                                    ok++;
-                                }
-
-                                v = out(source,
-                                        here, ok,
-                                        okAscent, okDescent, okTop, okBottom,
-                                        v,
-                                        spacingmult, spacingadd, chooseHt,
-                                        chooseHtv, fm, hasTabOrEmoji,
-                                        needMultiply, paraStart, chdirs, dir, easy,
-                                        ok == bufEnd, includepad, trackpad,
-                                        chs, widths, here - paraStart,
+                                        chs, widths, paraStart,
                                         ellipsize, ellipsizedWidth, okWidth,
                                         paint);
 
@@ -424,7 +386,7 @@
                                         chooseHtv, fm, hasTabOrEmoji,
                                         needMultiply, paraStart, chdirs, dir, easy,
                                         fit == bufEnd, includepad, trackpad,
-                                        chs, widths, here - paraStart,
+                                        chs, widths, paraStart,
                                         ellipsize, ellipsizedWidth, fitWidth,
                                         paint);
 
@@ -446,13 +408,12 @@
                                         needMultiply, paraStart, chdirs, dir, easy,
                                         here + 1 == bufEnd, includepad,
                                         trackpad,
-                                        chs, widths, here - paraStart,
+                                        chs, widths, paraStart,
                                         ellipsize, ellipsizedWidth,
                                         widths[here - paraStart], paint);
 
                                 here = here + 1;
                             }
-                        }
 
                         if (here < spanStart) {
                             // didn't output all the text for this span
@@ -495,7 +456,7 @@
                         chooseHtv, fm, hasTabOrEmoji,
                         needMultiply, paraStart, chdirs, dir, easy,
                         paraEnd == bufEnd, includepad, trackpad,
-                        chs, widths, here - paraStart,
+                        chs, widths, paraStart,
                         ellipsize, ellipsizedWidth, w, paint);
             }
 
@@ -614,19 +575,6 @@
         return false;
     }
 
-/*
-    private static void dump(byte[] data, int count, String label) {
-        if (false) {
-            System.out.print(label);
-
-            for (int i = 0; i < count; i++)
-                System.out.print(" " + data[i]);
-
-            System.out.println();
-        }
-    }
-*/
-
     private int out(CharSequence text, int start, int end,
                       int above, int below, int top, int bottom, int v,
                       float spacingmult, float spacingadd,
@@ -729,8 +677,8 @@
         if (easy) {
             mLineDirections[j] = linedirs;
         } else {
-            mLineDirections[j] = AndroidBidi.directions(dir, chdirs, widthStart, chs,
-                    widthStart, end - start);
+            mLineDirections[j] = AndroidBidi.directions(dir, chdirs, start - widthStart, chs,
+                    start - widthStart, end - start);
         }
 
         // If ellipsize is in marquee mode, do not apply ellipsis on the first line
@@ -869,7 +817,7 @@
     @Override
     public int getLineDescent(int line) {
         int descent = mLines[mColumns * line + DESCENT];
-        if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount - 1 &&
+        if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount - 1 && // -1 intended
                 line != mLineCount) {
             descent += getBottomPadding();
         }
@@ -933,8 +881,8 @@
      * @hide
      */
     @Override
-    public void setMaximumVisibleLineCount(int line) {
-        mMaximumVisibleLineCount = line;
+    public void setMaximumVisibleLineCount(int lineCount) {
+        mMaximumVisibleLineCount = lineCount;
     }
 
     private int mLineCount;
diff --git a/core/java/android/util/AttributeSet.java b/core/java/android/util/AttributeSet.java
index 82592b9..470526c 100644
--- a/core/java/android/util/AttributeSet.java
+++ b/core/java/android/util/AttributeSet.java
@@ -56,10 +56,53 @@
  * identifier associated with a particular XML attribute name.
  */
 public interface AttributeSet {
+    /**
+     * Returns the number of attributes available in the set.
+     * 
+     * @return A positive integer, or 0 if the set is empty.
+     */
     public int getAttributeCount();
+
+    /**
+     * Returns the name of the specified attribute.
+     * 
+     * @param index Index of the desired attribute, 0...count-1.
+     * 
+     * @return A String containing the name of the attribute, or null if the
+     *         attribute cannot be found.
+     */
     public String getAttributeName(int index);
+
+    /**
+     * Returns the value of the specified attribute as a string representation.
+     * 
+     * @param index Index of the desired attribute, 0...count-1.
+     * 
+     * @return A String containing the value of the attribute, or null if the
+     *         attribute cannot be found.
+     */
     public String getAttributeValue(int index);
+
+    /**
+     * Returns the value of the specified attribute as a string representation.
+     * The lookup is performed using the attribute name.
+     * 
+     * @param namespace The namespace of the attribute to get the value from.
+     * @param name The name of the attribute to get the value from.
+     * 
+     * @return A String containing the value of the attribute, or null if the
+     *         attribute cannot be found.
+     */
     public String getAttributeValue(String namespace, String name);
+
+    /**
+     * Returns a description of the current position of the attribute set.
+     * For instance, if the attribute set is loaded from an XML document,
+     * the position description could indicate the current line number.
+     * 
+     * @return A string representation of the current position in the set,
+     *         may be null.
+     */
     public String getPositionDescription();
 
     /**
@@ -80,7 +123,8 @@
 
     /**
      * Return the index of the value of 'attribute' in the list 'options'.
-     * 
+     *
+     * @param namespace Namespace of attribute to retrieve. 
      * @param attribute Name of attribute to retrieve.
      * @param options List of strings whose values we are checking against.
      * @param defaultValue Value returned if attribute doesn't exist or no
@@ -94,6 +138,7 @@
     /**
      * Return the boolean value of 'attribute'.
      * 
+     * @param namespace Namespace of attribute to retrieve.
      * @param attribute The attribute to retrieve.
      * @param defaultValue What to return if the attribute isn't found.
      * 
@@ -111,6 +156,7 @@
      * "@package:type/resource"); the other method returns a resource
      * identifier that identifies the name of the attribute.
      * 
+     * @param namespace Namespace of attribute to retrieve.
      * @param attribute The attribute to retrieve.
      * @param defaultValue What to return if the attribute isn't found.
      * 
@@ -122,6 +168,7 @@
     /**
      * Return the integer value of 'attribute'.
      * 
+     * @param namespace Namespace of attribute to retrieve.
      * @param attribute The attribute to retrieve.
      * @param defaultValue What to return if the attribute isn't found.
      * 
@@ -135,6 +182,7 @@
      * unsigned value.  In particular, the formats 0xn...n and #n...n are
      * handled.
      * 
+     * @param namespace Namespace of attribute to retrieve.
      * @param attribute The attribute to retrieve.
      * @param defaultValue What to return if the attribute isn't found.
      * 
@@ -146,6 +194,7 @@
     /**
      * Return the float value of 'attribute'.
      * 
+     * @param namespace Namespace of attribute to retrieve.
      * @param attribute The attribute to retrieve.
      * @param defaultValue What to return if the attribute isn't found.
      * 
@@ -165,8 +214,7 @@
      * 
      * @return Index in to 'options' or defaultValue.
      */
-    public int getAttributeListValue(int index,
-                                     String[] options, int defaultValue);
+    public int getAttributeListValue(int index, String[] options, int defaultValue);
 
     /**
      * Return the boolean value of attribute at 'index'.
@@ -176,8 +224,7 @@
      * 
      * @return Resulting value.
      */
-    public boolean getAttributeBooleanValue(int index,
-                                            boolean defaultValue);
+    public boolean getAttributeBooleanValue(int index, boolean defaultValue);
 
     /**
      * Return the value of attribute at 'index' as a resource identifier.
@@ -193,8 +240,7 @@
      * 
      * @return Resulting value.
      */
-    public int getAttributeResourceValue(int index,
-                                         int defaultValue);
+    public int getAttributeResourceValue(int index, int defaultValue);
 
     /**
      * Return the integer value of attribute at 'index'.
@@ -204,8 +250,7 @@
      * 
      * @return Resulting value.
      */
-    public int getAttributeIntValue(int index,
-                                    int defaultValue);
+    public int getAttributeIntValue(int index, int defaultValue);
 
     /**
      * Return the integer value of attribute at 'index' that is formatted as an
@@ -217,8 +262,7 @@
      * 
      * @return Resulting value.
      */
-    public int getAttributeUnsignedIntValue(int index,
-                                            int defaultValue);
+    public int getAttributeUnsignedIntValue(int index, int defaultValue);
 
     /**
      * Return the float value of attribute at 'index'.
@@ -228,8 +272,7 @@
      * 
      * @return Resulting value.
      */
-    public float getAttributeFloatValue(int index,
-                                        float defaultValue);
+    public float getAttributeFloatValue(int index, float defaultValue);
 
     /**
      * Return the value of the "id" attribute or null if there is not one.
@@ -266,4 +309,3 @@
      */
     public int getStyleAttribute();
 }
-
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 51653df..dd8242a 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -100,6 +100,8 @@
     void disableKeyguard(IBinder token, String tag);
     void reenableKeyguard(IBinder token);
     void exitKeyguardSecurely(IOnKeyguardExitResult callback);
+    boolean isKeyguardLocked();
+    boolean isKeyguardSecure();
     boolean inKeyguardRestrictedInputMode();
 
     void closeSystemDialogs(String reason);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index eefce06..e00b9cd 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5748,9 +5748,7 @@
                 }
                 mCamera.save();
                 mMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY);
-                mCamera.rotateX(mRotationX);
-                mCamera.rotateY(mRotationY);
-                mCamera.rotateZ(-mRotation);
+                mCamera.rotate(mRotationX, mRotationY, -mRotation);
                 mCamera.getMatrix(matrix3D);
                 matrix3D.preTranslate(-mPivotX, -mPivotY);
                 matrix3D.postTranslate(mPivotX + mTranslationX, mPivotY + mTranslationY);
@@ -6665,7 +6663,14 @@
      * view specifying how it should be arranged. There are many subclasses of
      * ViewGroup.LayoutParams, and these correspond to the different subclasses
      * of ViewGroup that are responsible for arranging their children.
-     * @return The LayoutParams associated with this view
+     *
+     * This method may return null if this View is not attached to a parent
+     * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)}
+     * was not invoked successfully. When a View is attached to a parent
+     * ViewGroup, this method must not return null.
+     *
+     * @return The LayoutParams associated with this view, or null if no
+     *         parameters have been set yet
      */
     @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_")
     public ViewGroup.LayoutParams getLayoutParams() {
@@ -6679,11 +6684,11 @@
      * correspond to the different subclasses of ViewGroup that are responsible
      * for arranging their children.
      *
-     * @param params the layout parameters for this view
+     * @param params The layout parameters for this view, cannot be null
      */
     public void setLayoutParams(ViewGroup.LayoutParams params) {
         if (params == null) {
-            throw new NullPointerException("params == null");
+            throw new NullPointerException("Layout parameters cannot be null");
         }
         mLayoutParams = params;
         requestLayout();
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index ad06902..be68cb9 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -754,6 +754,24 @@
     void exitKeyguardSecurely(OnKeyguardExitResult callback);
 
     /**
+     * isKeyguardLocked
+     *
+     * Return whether the keyguard is currently locked.
+     *
+     * @return true if in keyguard is locked.
+     */
+    public boolean isKeyguardLocked();
+
+    /**
+     * isKeyguardSecure
+     *
+     * Return whether the keyguard requires a password to unlock.
+     *
+     * @return true if in keyguard is secure.
+     */
+    public boolean isKeyguardSecure();
+
+    /**
      * inKeyguardRestrictedKeyInputMode
      *
      * if keyguard screen is showing or in restricted key input mode (i.e. in
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index cb67b78..a39c7c7 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -762,8 +762,7 @@
      * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
      * {@link #RESULT_HIDDEN}.
      */
-    public boolean showSoftInput(View view, int flags,
-            ResultReceiver resultReceiver) {
+    public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
         checkFocus();
         synchronized (mH) {
             if (mServedView != view && (mServedView == null
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 3caf345..2cc3881 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -77,6 +77,7 @@
     private static final int PAUSED            = 203;
 
     private static final String COOKIE = "Cookie";
+    private static final String HIDE_URL_LOGS = "x-hide-urls-from-log";
 
     // Timer thread -> UI thread
     private static final int TIMEUPDATE = 300;
@@ -184,11 +185,13 @@
             mVideoView.setMediaController(new MediaController(proxy.getContext()));
 
             String cookieValue = CookieManager.getInstance().getCookie(url);
-            Map<String, String> headers = null;
+            Map<String, String> headers = new HashMap<String, String>();
             if (cookieValue != null) {
-                headers = new HashMap<String, String>();
                 headers.put(COOKIE, cookieValue);
             }
+            if (mCurrentProxy.getWebView().isPrivateBrowsingEnabled()) {
+                headers.put(HIDE_URL_LOGS, "true");
+            }
 
             mVideoView.setVideoURI(Uri.parse(url), headers);
             mVideoView.setOnCompletionListener(proxy);
diff --git a/core/java/android/webkit/SelectActionModeCallback.java b/core/java/android/webkit/SelectActionModeCallback.java
index ea09fc0..104deb1 100644
--- a/core/java/android/webkit/SelectActionModeCallback.java
+++ b/core/java/android/webkit/SelectActionModeCallback.java
@@ -83,6 +83,7 @@
             case com.android.internal.R.id.websearch:
                 mode.finish();
                 Intent i = new Intent(Intent.ACTION_WEB_SEARCH);
+                i.putExtra(SearchManager.EXTRA_NEW_SEARCH, true);
                 i.putExtra(SearchManager.QUERY, mWebView.getSelection());
                 mWebView.getContext().startActivity(i);
                 break;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 74e6628..a11d674 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1339,11 +1339,12 @@
         }
     }
 
-    /*
+    /**
      * returns the height of the titlebarview (if any). Does not care about
      * scrolling
+     * @hide
      */
-    int getTitleHeight() {
+    protected int getTitleHeight() {
         return mTitleBar != null ? mTitleBar.getHeight() : 0;
     }
 
@@ -3710,7 +3711,7 @@
             } else if (mTitleGravity == Gravity.TOP) {
                 newTop = mScrollY;
             }
-            mTitleBar.setBottom(newTop + getTitleHeight());
+            mTitleBar.setBottom(newTop + mTitleBar.getHeight());
             mTitleBar.setTop(newTop);
         }
         return super.drawChild(canvas, child, drawingTime);
@@ -3790,7 +3791,7 @@
             drawOverScrollBackground(canvas);
         }
         if (mTitleBar != null) {
-            canvas.translate(0, (int) mTitleBar.getHeight());
+            canvas.translate(0, getTitleHeight());
         }
         drawContent(canvas);
         canvas.restoreToCount(saveCount);
@@ -5531,6 +5532,8 @@
                         ted.mPoints[0] = new Point(contentX, contentY);
                         ted.mMetaState = ev.getMetaState();
                         ted.mReprocess = mDeferTouchProcess;
+                        ted.mNativeLayer = nativeScrollableLayer(
+                                contentX, contentY, ted.mNativeLayerRect, null);
                         mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                         if (mDeferTouchProcess) {
                             // still needs to set them for compute deltaX/Y
@@ -5575,6 +5578,8 @@
                     ted.mPoints[0] = new Point(contentX, contentY);
                     ted.mMetaState = ev.getMetaState();
                     ted.mReprocess = mDeferTouchProcess;
+                    ted.mNativeLayer = mScrollingLayer;
+                    ted.mNativeLayerRect.set(mScrollingLayerRect);
                     mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                     mLastSentTouchTime = eventTime;
                     if (mDeferTouchProcess) {
@@ -5754,6 +5759,8 @@
                     ted.mPoints[0] = new Point(contentX, contentY);
                     ted.mMetaState = ev.getMetaState();
                     ted.mReprocess = mDeferTouchProcess;
+                    ted.mNativeLayer = mScrollingLayer;
+                    ted.mNativeLayerRect.set(mScrollingLayerRect);
                     mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                 }
                 mLastTouchUpTime = eventTime;
@@ -5773,6 +5780,9 @@
                             ted.mPoints[0] = new Point(contentX, contentY);
                             ted.mMetaState = ev.getMetaState();
                             ted.mReprocess = mDeferTouchProcess;
+                            ted.mNativeLayer = nativeScrollableLayer(
+                                    contentX, contentY,
+                                    ted.mNativeLayerRect, null);
                             mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                         } else if (mPreventDefault != PREVENT_DEFAULT_YES){
                             mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
@@ -6004,6 +6014,8 @@
             ted.mPoints = new Point[1];
             ted.mPoints[0] = new Point(x, y);
             ted.mAction = MotionEvent.ACTION_CANCEL;
+            ted.mNativeLayer = nativeScrollableLayer(
+                    x, y, ted.mNativeLayerRect, null);
             mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
             mPreventDefault = PREVENT_DEFAULT_IGNORE;
         }
@@ -6643,8 +6655,9 @@
         // mLastTouchX and mLastTouchY are the point in the current viewport
         int contentX = viewToContentX(mLastTouchX + mScrollX);
         int contentY = viewToContentY(mLastTouchY + mScrollY);
-        Rect rect = new Rect(contentX - mNavSlop, contentY - mNavSlop,
-                contentX + mNavSlop, contentY + mNavSlop);
+        int slop = viewToContentDimension(mNavSlop);
+        Rect rect = new Rect(contentX - slop, contentY - slop,
+                contentX + slop, contentY + slop);
         nativeSelectBestAt(rect);
         mInitialHitTestResult = hitTestResult(null);
     }
@@ -6718,7 +6731,8 @@
         }
         int x = viewToContentX((int) event.getX() + mWebTextView.getLeft());
         int y = viewToContentY((int) event.getY() + mWebTextView.getTop());
-        nativeMotionUp(x, y, mNavSlop);
+        int slop = viewToContentDimension(mNavSlop);
+        nativeMotionUp(x, y, slop);
     }
 
     /**
@@ -6741,6 +6755,7 @@
         // mLastTouchX and mLastTouchY are the point in the current viewport
         int contentX = viewToContentX(mLastTouchX + mScrollX);
         int contentY = viewToContentY(mLastTouchY + mScrollY);
+        int slop = viewToContentDimension(mNavSlop);
         if (getSettings().supportTouchOnly()) {
             removeTouchHighlight(false);
             WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
@@ -6748,7 +6763,7 @@
             // it used when processing GET_TOUCH_HIGHLIGHT_RECTS
             touchUpData.mMoveGeneration = 0;
             mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
-        } else if (nativePointInNavCache(contentX, contentY, mNavSlop)) {
+        } else if (nativePointInNavCache(contentX, contentY, slop)) {
             WebViewCore.MotionUpData motionUpData = new WebViewCore
                     .MotionUpData();
             motionUpData.mFrame = nativeCacheHitFramePointer();
@@ -6764,7 +6779,8 @@
     }
 
     private void doMotionUp(int contentX, int contentY) {
-        if (nativeMotionUp(contentX, contentY, mNavSlop) && mLogEvent) {
+        int slop = viewToContentDimension(mNavSlop);
+        if (nativeMotionUp(contentX, contentY, slop) && mLogEvent) {
             EventLog.writeEvent(EventLogTags.BROWSER_SNAP_CENTER);
         }
         if (nativeHasCursorNode() && !nativeCursorIsTextInput()) {
@@ -6777,7 +6793,8 @@
      * plugin. Otherwise a NULL rectangle is returned.
      */
     Rect getPluginBounds(int x, int y) {
-        if (nativePointInNavCache(x, y, mNavSlop) && nativeCacheHitIsPlugin()) {
+        int slop = viewToContentDimension(mNavSlop);
+        if (nativePointInNavCache(x, y, slop) && nativeCacheHitIsPlugin()) {
             return nativeCacheHitNodeBounds();
         } else {
             return null;
@@ -7161,6 +7178,9 @@
                         // simplicity for now, we don't set it.
                         ted.mMetaState = 0;
                         ted.mReprocess = mDeferTouchProcess;
+                        ted.mNativeLayer = nativeScrollableLayer(
+                                ted.mPoints[0].x, ted.mPoints[0].y,
+                                ted.mNativeLayerRect, null);
                         mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                     } else if (mPreventDefault != PREVENT_DEFAULT_YES) {
                         mTouchMode = TOUCH_DONE_MODE;
@@ -8033,6 +8053,8 @@
         touchUpData.mNode = node;
         touchUpData.mX = x;
         touchUpData.mY = y;
+        touchUpData.mNativeLayer = nativeScrollableLayer(
+                x, y, touchUpData.mNativeLayerRect, null);
         mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
     }
 
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index da4ce43..fb0f61c 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -778,6 +778,8 @@
         int mNode;
         int mX;
         int mY;
+        int mNativeLayer;
+        Rect mNativeLayerRect = new Rect();
     }
 
     static class TouchHighlightData {
@@ -821,6 +823,8 @@
         int mMetaState;
         boolean mReprocess;
         MotionEvent mMotionEvent;
+        int mNativeLayer;
+        Rect mNativeLayerRect = new Rect();
     }
 
     static class GeolocationPermissionsData {
@@ -1304,6 +1308,10 @@
 
                         case TOUCH_UP:
                             TouchUpData touchUpData = (TouchUpData) msg.obj;
+                            if (touchUpData.mNativeLayer != 0) {
+                                nativeScrollLayer(touchUpData.mNativeLayer,
+                                        touchUpData.mNativeLayerRect);
+                            }
                             nativeTouchUp(touchUpData.mMoveGeneration,
                                     touchUpData.mFrame, touchUpData.mNode,
                                     touchUpData.mX, touchUpData.mY);
@@ -1318,6 +1326,10 @@
                                 xArray[c] = ted.mPoints[c].x;
                                 yArray[c] = ted.mPoints[c].y;
                             }
+                            if (ted.mNativeLayer != 0) {
+                                nativeScrollLayer(ted.mNativeLayer,
+                                        ted.mNativeLayerRect);
+                            }
                             Message.obtain(
                                     mWebView.mPrivateHandler,
                                     WebView.PREVENT_TOUCH_ID,
@@ -2702,4 +2714,5 @@
             int slop);
 
    private native void nativeAutoFillForm(int queryId);
+   private native void nativeScrollLayer(int layer, Rect rect);
 }
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index a84df16..0383b5c 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -37,14 +37,46 @@
  *
  * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-gridview.html">Grid
  * View tutorial</a>.</p>
+ * 
+ * @attr ref android.R.styleable#GridView_horizontalSpacing
+ * @attr ref android.R.styleable#GridView_verticalSpacing
+ * @attr ref android.R.styleable#GridView_stretchMode
+ * @attr ref android.R.styleable#GridView_columnWidth
+ * @attr ref android.R.styleable#GridView_numColumns
+ * @attr ref android.R.styleable#GridView_gravity
  */
 @RemoteView
 public class GridView extends AbsListView {
+    /**
+     * Disables stretching.
+     * 
+     * @see #setStretchMode(int) 
+     */
     public static final int NO_STRETCH = 0;
+    /**
+     * Stretches the spacing between columns.
+     * 
+     * @see #setStretchMode(int) 
+     */
     public static final int STRETCH_SPACING = 1;
+    /**
+     * Stretches columns.
+     * 
+     * @see #setStretchMode(int) 
+     */
     public static final int STRETCH_COLUMN_WIDTH = 2;
+    /**
+     * Stretches the spacing between columns. The spacing is uniform.
+     * 
+     * @see #setStretchMode(int) 
+     */
     public static final int STRETCH_SPACING_UNIFORM = 3;
-    
+
+    /**
+     * Creates as many columns as can fit on screen.
+     * 
+     * @see #setNumColumns(int) 
+     */
     public static final int AUTO_FIT = -1;
 
     private int mNumColumns = AUTO_FIT;
diff --git a/core/java/android/widget/ListAdapter.java b/core/java/android/widget/ListAdapter.java
index 0fd2e70..d8fd1c9 100644
--- a/core/java/android/widget/ListAdapter.java
+++ b/core/java/android/widget/ListAdapter.java
@@ -26,10 +26,14 @@
 public interface ListAdapter extends Adapter {
 
     /**
-     * Are all items in this ListAdapter enabled?
-     * If yes it means all items are selectable and clickable.
+     * Indicates whether all the items in this adapter are enabled. If the
+     * value returned by this method changes over time, there is no guarantee
+     * it will take effect.  If true, it means all items are selectable and
+     * clickable (there is no separator.)
      * 
-     * @return True if all items are enabled
+     * @return True if all items are enabled, false otherwise.
+     * 
+     * @see #isEnabled(int) 
      */
     public boolean areAllItemsEnabled();
 
@@ -41,7 +45,10 @@
      * should be thrown in that case for fast failure.
      *
      * @param position Index of the item
+     * 
      * @return True if the item is not a separator
+     * 
+     * @see #areAllItemsEnabled() 
      */
     boolean isEnabled(int position);
 }
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 4b858d0..9002b1d 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -378,8 +378,7 @@
      * <p>Change the popup's content. The content is represented by an instance
      * of {@link android.view.View}.</p>
      *
-     * <p>This method has no effect if called when the popup is showing.  To
-     * apply it while a popup is showing, call </p>
+     * <p>This method has no effect if called when the popup is showing.</p>
      *
      * @param contentView the new content for the popup
      *
@@ -1040,7 +1039,7 @@
      *
      * @return true if the popup is translated upwards to fit on screen
      */
-    private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
+    boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
             int xoff, int yoff) {
 
         anchor.getLocationInWindow(mDrawingLocation);
@@ -1374,6 +1373,7 @@
      * height can be set to -1 to update location only.  Calling this function
      * also updates the window with the current popup state as
      * described for {@link #update()}.</p>
+     *
      * <p>If the view later scrolls to move <code>anchor</code> to a different
      * location, the popup will be moved correspondingly.</p>
      *
@@ -1395,9 +1395,13 @@
         }
 
         WeakReference<View> oldAnchor = mAnchor;
-        if (oldAnchor == null || oldAnchor.get() != anchor ||
-                (updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff))) {
+        final boolean needsUpdate = updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff);
+        if (oldAnchor == null || oldAnchor.get() != anchor || (needsUpdate && !mIsDropdown)) {
             registerForScrollChanged(anchor, xoff, yoff);
+        } else if (needsUpdate) {
+            // No need to register again if this is a DropDown, showAsDropDown already did.
+            mAnchorXoff = xoff;
+            mAnchorYoff = yoff;
         }
 
         WindowManager.LayoutParams p = (WindowManager.LayoutParams) mPopupView.getLayoutParams();
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index ef4e4e0..cf72ec4 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -701,8 +701,8 @@
 
             if (mProgress > max) {
                 mProgress = max;
-                refreshProgress(R.id.progress, mProgress, false);
             }
+            refreshProgress(R.id.progress, mProgress, false);
         }
     }
     
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d90d5be..6791a1d 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -46,7 +46,6 @@
 import android.os.Message;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.ResultReceiver;
 import android.os.SystemClock;
 import android.text.BoringLayout;
 import android.text.DynamicLayout;
@@ -3874,9 +3873,6 @@
 
     private void registerForPreDraw() {
         final ViewTreeObserver observer = getViewTreeObserver();
-        if (observer == null) {
-            return;
-        }
 
         if (mPreDrawState == PREDRAW_NOT_REGISTERED) {
             observer.addOnPreDrawListener(this);
@@ -3962,15 +3958,13 @@
         }
 
         final ViewTreeObserver observer = getViewTreeObserver();
-        if (observer != null) {
-            // No need to create the controller.
-            // The get method will add the listener on controller creation.
-            if (mInsertionPointCursorController != null) {
-                observer.addOnTouchModeChangeListener(mInsertionPointCursorController);
-            }
-            if (mSelectionModifierCursorController != null) {
-                observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
-            }
+        // No need to create the controller.
+        // The get method will add the listener on controller creation.
+        if (mInsertionPointCursorController != null) {
+            observer.addOnTouchModeChangeListener(mInsertionPointCursorController);
+        }
+        if (mSelectionModifierCursorController != null) {
+            observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
         }
     }
 
@@ -3979,18 +3973,16 @@
         super.onDetachedFromWindow();
 
         final ViewTreeObserver observer = getViewTreeObserver();
-        if (observer != null) {
-            if (mPreDrawState != PREDRAW_NOT_REGISTERED) {
-                observer.removeOnPreDrawListener(this);
-                mPreDrawState = PREDRAW_NOT_REGISTERED;
-            }
-            // No need to create the controller, as getXXController would.
-            if (mInsertionPointCursorController != null) {
-                observer.removeOnTouchModeChangeListener(mInsertionPointCursorController);
-            }
-            if (mSelectionModifierCursorController != null) {
-                observer.removeOnTouchModeChangeListener(mSelectionModifierCursorController);
-            }
+        if (mPreDrawState != PREDRAW_NOT_REGISTERED) {
+            observer.removeOnPreDrawListener(this);
+            mPreDrawState = PREDRAW_NOT_REGISTERED;
+        }
+        // No need to create the controller, as getXXController would.
+        if (mInsertionPointCursorController != null) {
+            observer.removeOnTouchModeChangeListener(mInsertionPointCursorController);
+        }
+        if (mSelectionModifierCursorController != null) {
+            observer.removeOnTouchModeChangeListener(mSelectionModifierCursorController);
         }
 
         if (mError != null) {
@@ -3998,7 +3990,7 @@
         }
 
         if (mBlink != null) {
-            mBlink.cancel();
+            mBlink.removeCallbacks(mBlink);
         }
 
         if (mInsertionPointCursorController != null) {
@@ -4291,10 +4283,8 @@
 
         if (mPreDrawState == PREDRAW_DONE) {
             final ViewTreeObserver observer = getViewTreeObserver();
-            if (observer != null) {
-                observer.removeOnPreDrawListener(this);
-                mPreDrawState = PREDRAW_NOT_REGISTERED;
-            }
+            observer.removeOnPreDrawListener(this);
+            mPreDrawState = PREDRAW_NOT_REGISTERED;
         }
 
         int color = mCurTextColor;
@@ -5422,18 +5412,13 @@
         invalidate();
         int curs = getSelectionStart();
 
-        if (curs >= 0 || (mGravity & Gravity.VERTICAL_GRAVITY_MASK) ==
-                             Gravity.BOTTOM) {
+        if (curs >= 0 || (mGravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM) {
             registerForPreDraw();
         }
 
         if (curs >= 0) {
             mHighlightPathBogus = true;
-
-            if (isFocused()) {
-                mShowCursor = SystemClock.uptimeMillis();
-                makeBlink();
-            }
+            makeBlink();
         }
 
         checkForResize();
@@ -5547,8 +5532,7 @@
                     ellipsisWidth);
         } else {
             if (boring == UNKNOWN_BORING) {
-                boring = BoringLayout.isBoring(mTransformed, mTextPaint,
-                                               mBoring);
+                boring = BoringLayout.isBoring(mTransformed, mTextPaint, mBoring);
                 if (boring != null) {
                     mBoring = boring;
                 }
@@ -6590,13 +6574,15 @@
      */
     @android.view.RemotableViewMethod
     public void setCursorVisible(boolean visible) {
-        mCursorVisible = visible;
-        invalidate();
+        if (mCursorVisible != visible) {
+            mCursorVisible = visible;
+            invalidate();
 
-        makeBlink();
+            makeBlink();
 
-        // InsertionPointCursorController depends on mCursorVisible
-        prepareCursorControllers();
+            // InsertionPointCursorController depends on mCursorVisible
+            prepareCursorControllers();
+        }
     }
 
     private boolean isCursorVisible() {
@@ -6935,11 +6921,7 @@
             if (oldStart >= 0 || newStart >= 0) {
                 invalidateCursor(Selection.getSelectionStart(buf), oldStart, newStart);
                 registerForPreDraw();
-
-                if (isFocused()) {
-                    mShowCursor = SystemClock.uptimeMillis();
-                    makeBlink();
-                }
+                makeBlink();
             }
         }
 
@@ -7090,22 +7072,6 @@
         }
     }
 
-    private void makeBlink() {
-        if (!isCursorVisible()) {
-            if (mBlink != null) {
-                mBlink.removeCallbacks(mBlink);
-            }
-
-            return;
-        }
-
-        if (mBlink == null)
-            mBlink = new Blink(this);
-
-        mBlink.removeCallbacks(mBlink);
-        mBlink.postAtTime(mBlink, mShowCursor + BLINK);
-    }
-
     /**
      * @hide
      */
@@ -7243,7 +7209,7 @@
         // does not happen in that case (using the arrows on a bluetooth keyboard).
         if (focused && isTextEditable()) {
             final InputMethodManager imm = InputMethodManager.peekInstance();
-            if (imm != null) imm.showSoftInput(this, 0, null);
+            if (imm != null) imm.showSoftInput(this, 0);
         }
     }
 
@@ -7272,11 +7238,7 @@
         if (hasWindowFocus) {
             if (mBlink != null) {
                 mBlink.uncancel();
-
-                if (isFocused()) {
-                    mShowCursor = SystemClock.uptimeMillis();
-                    makeBlink();
-                }
+                makeBlink();
             }
         } else {
             if (mBlink != null) {
@@ -7327,33 +7289,6 @@
         }
     }
 
-    class CommitSelectionReceiver extends ResultReceiver {
-        private final int mPrevStart, mPrevEnd;
-
-        public CommitSelectionReceiver(int prevStart, int prevEnd) {
-            super(getHandler());
-            mPrevStart = prevStart;
-            mPrevEnd = prevEnd;
-        }
-
-        @Override
-        protected void onReceiveResult(int resultCode, Bundle resultData) {
-            // If this tap was actually used to show the IMM, leave cursor or selection unchanged
-            // by restoring its previous position.
-            if (resultCode == InputMethodManager.RESULT_SHOWN) {
-                final int len = mText.length();
-                int start = Math.min(len, mPrevStart);
-                int end = Math.min(len, mPrevEnd);
-                Selection.setSelection((Spannable)mText, start, end);
-
-                boolean selectAllGotFocus = mSelectAllOnFocus && mTouchFocusSelected;
-                if (hasSelection() && !selectAllGotFocus) {
-                    startSelectionActionMode();
-                }
-            }
-        }
-    }
-
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         final int action = event.getActionMasked();
@@ -7394,10 +7329,6 @@
                 && mText instanceof Spannable && mLayout != null) {
             boolean handled = false;
 
-            // Save previous selection, in case this event is used to show the IME.
-            int oldSelStart = getSelectionStart();
-            int oldSelEnd = getSelectionEnd();
-
             final int oldScrollX = mScrollX;
             final int oldScrollY = mScrollY;
 
@@ -7429,22 +7360,21 @@
                 }
 
                 if (touchIsFinished) {
-                    CommitSelectionReceiver csr = null;
-                    if (getSelectionStart() != oldSelStart || getSelectionEnd() != oldSelEnd ||
-                            didTouchFocusSelect()) {
-                        csr = new CommitSelectionReceiver(oldSelStart, oldSelEnd);
-                    }
-
                     // Show the IME, except when selecting in read-only text.
                     if (!mTextIsSelectable) {
                         final InputMethodManager imm = InputMethodManager.peekInstance();
-                        handled |= imm != null && imm.showSoftInput(this, 0, csr) && (csr != null);
+                        handled |= imm != null && imm.showSoftInput(this, 0);
                     }
 
-                    stopSelectionActionMode();
-                    boolean selectAllGotFocus = mSelectAllOnFocus && mTouchFocusSelected;
-                    if (hasInsertionController() && !selectAllGotFocus && mText.length() > 0) {
-                        getInsertionController().show();
+
+                    boolean selectAllGotFocus = mSelectAllOnFocus && didTouchFocusSelect();
+                    if (!selectAllGotFocus && hasSelection()) {
+                        startSelectionActionMode();
+                    } else {
+                        stopSelectionActionMode();
+                        if (hasInsertionController() && !selectAllGotFocus && mText.length() > 0) {
+                            getInsertionController().show();
+                        }
                     }
                 }
             }
@@ -7545,17 +7475,12 @@
 
             TextView tv = mView.get();
 
-            if (tv != null && tv.isFocused()) {
-                int st = tv.getSelectionStart();
-                int en = tv.getSelectionEnd();
-
-                if (st == en && st >= 0 && en >= 0) {
-                    if (tv.mLayout != null) {
-                        tv.invalidateCursorPath();
-                    }
-
-                    postAtTime(this, SystemClock.uptimeMillis() + BLINK);
+            if (tv != null && tv.shouldBlink()) {
+                if (tv.mLayout != null) {
+                    tv.invalidateCursorPath();
                 }
+
+                postAtTime(this, SystemClock.uptimeMillis() + BLINK);
             }
         }
 
@@ -7571,6 +7496,34 @@
         }
     }
 
+    /**
+     * @return True when the TextView isFocused and has a valid zero-length selection (cursor).
+     */
+    private boolean shouldBlink() {
+        if (!isFocused()) return false;
+
+        final int start = getSelectionStart();
+        if (start < 0) return false;
+
+        final int end = getSelectionEnd();
+        if (end < 0) return false;
+
+        return start == end;
+    }
+
+    private void makeBlink() {
+        if (isCursorVisible()) {
+            if (shouldBlink()) {
+                mShowCursor = SystemClock.uptimeMillis();
+                if (mBlink == null) mBlink = new Blink(this);
+                mBlink.removeCallbacks(mBlink);
+                mBlink.postAtTime(mBlink, mShowCursor + BLINK);
+            }
+        } else {
+            if (mBlink != null) mBlink.removeCallbacks(mBlink);
+        }
+    }
+
     @Override
     protected float getLeftFadingEdgeStrength() {
         if (mCurrentAlpha <= ViewConfiguration.ALPHA_THRESHOLD_INT) return 0.0f;
@@ -8692,9 +8645,9 @@
         }
     }
 
-    private class HandleView extends View {
+    private class HandleView extends View implements ViewTreeObserver.OnScrollChangedListener {
         private Drawable mDrawable;
-        private final PopupWindow mContainer;
+        private final ScrollingPopupWindow mContainer;
         private int mPositionX;
         private int mPositionY;
         private final CursorController mController;
@@ -8715,7 +8668,8 @@
 
         // Touch-up filter: number of previous positions remembered
         private static final int HISTORY_SIZE = 5;
-        private static final int TOUCH_UP_FILTER_DELAY = 150;
+        private static final int TOUCH_UP_FILTER_DELAY_AFTER = 150;
+        private static final int TOUCH_UP_FILTER_DELAY_BEFORE = 350;
         private final long[] mPreviousOffsetsTimes = new long[HISTORY_SIZE];
         private final int[] mPreviousOffsets = new int[HISTORY_SIZE];
         private int mPreviousOffsetIndex = 0;
@@ -8742,15 +8696,17 @@
         public void filterOnTouchUp() {
             final long now = SystemClock.uptimeMillis();
             int i = 0;
-            int index = 0;
+            int index = mPreviousOffsetIndex;
             final int iMax = Math.min(mNumberPreviousOffsets, HISTORY_SIZE);
-            while (i < iMax) {
-                index = (mPreviousOffsetIndex - i + HISTORY_SIZE) % HISTORY_SIZE;
-                if ((now - mPreviousOffsetsTimes[index]) >= TOUCH_UP_FILTER_DELAY) break;
+            while (i < iMax && (now - mPreviousOffsetsTimes[index]) < TOUCH_UP_FILTER_DELAY_AFTER) {
                 i++;
+                index = (mPreviousOffsetIndex - i + HISTORY_SIZE) % HISTORY_SIZE;
             }
 
-            mController.updateOffset(this, mPreviousOffsets[index]);
+            if (i > 0 && i < iMax &&
+                    (now - mPreviousOffsetsTimes[index]) > TOUCH_UP_FILTER_DELAY_BEFORE) {
+                mController.updateOffset(this, mPreviousOffsets[index]);
+            }
         }
 
         public static final int LEFT = 0;
@@ -8760,7 +8716,7 @@
         public HandleView(CursorController controller, int pos) {
             super(TextView.this.mContext);
             mController = controller;
-            mContainer = new PopupWindow(TextView.this.mContext, null,
+            mContainer = new ScrollingPopupWindow(TextView.this.mContext, null,
                     com.android.internal.R.attr.textSelectHandleWindowStyle);
             mContainer.setSplitTouchEnabled(true);
             mContainer.setClippingEnabled(false);
@@ -8772,40 +8728,40 @@
         public void setOrientation(int pos) {
             int handleWidth;
             switch (pos) {
-            case LEFT: {
-                if (mSelectHandleLeft == null) {
-                    mSelectHandleLeft = mContext.getResources().getDrawable(
-                            mTextSelectHandleLeftRes);
+                case LEFT: {
+                    if (mSelectHandleLeft == null) {
+                        mSelectHandleLeft = mContext.getResources().getDrawable(
+                                mTextSelectHandleLeftRes);
+                    }
+                    mDrawable = mSelectHandleLeft;
+                    handleWidth = mDrawable.getIntrinsicWidth();
+                    mHotspotX = handleWidth * 3.0f / 4.0f;
+                    break;
                 }
-                mDrawable = mSelectHandleLeft;
-                handleWidth = mDrawable.getIntrinsicWidth();
-                mHotspotX = handleWidth * 3.0f / 4.0f;
-                break;
-            }
 
-            case RIGHT: {
-                if (mSelectHandleRight == null) {
-                    mSelectHandleRight = mContext.getResources().getDrawable(
-                            mTextSelectHandleRightRes);
+                case RIGHT: {
+                    if (mSelectHandleRight == null) {
+                        mSelectHandleRight = mContext.getResources().getDrawable(
+                                mTextSelectHandleRightRes);
+                    }
+                    mDrawable = mSelectHandleRight;
+                    handleWidth = mDrawable.getIntrinsicWidth();
+                    mHotspotX = handleWidth / 4.0f;
+                    break;
                 }
-                mDrawable = mSelectHandleRight;
-                handleWidth = mDrawable.getIntrinsicWidth();
-                mHotspotX = handleWidth / 4.0f;
-                break;
-            }
 
-            case CENTER:
-            default: {
-                if (mSelectHandleCenter == null) {
-                    mSelectHandleCenter = mContext.getResources().getDrawable(
-                            mTextSelectHandleRes);
+                case CENTER:
+                default: {
+                    if (mSelectHandleCenter == null) {
+                        mSelectHandleCenter = mContext.getResources().getDrawable(
+                                mTextSelectHandleRes);
+                    }
+                    mDrawable = mSelectHandleCenter;
+                    handleWidth = mDrawable.getIntrinsicWidth();
+                    mHotspotX = handleWidth / 2.0f;
+                    mIsInsertionHandle = true;
+                    break;
                 }
-                mDrawable = mSelectHandleCenter;
-                handleWidth = mDrawable.getIntrinsicWidth();
-                mHotspotX = handleWidth / 2.0f;
-                mIsInsertionHandle = true;
-                break;
-            }
             }
 
             final int handleHeight = mDrawable.getIntrinsicHeight();
@@ -8828,24 +8784,18 @@
                 return;
             }
             mContainer.setContentView(this);
-            final int[] coords = mTempCoords;
-            TextView.this.getLocationInWindow(coords);
-            mContainerPositionX = coords[0] + mPositionX;
-            mContainerPositionY = coords[1] + mPositionY;
-            mContainer.showAtLocation(TextView.this, 0, mContainerPositionX, mContainerPositionY);
+            mContainerPositionX = mPositionX;
+            mContainerPositionY = mPositionY - TextView.this.getHeight();
+            mContainer.showAsDropDown(TextView.this, mContainerPositionX, mContainerPositionY);
 
             // Hide paste view when handle is moved on screen.
-            if (mPastePopupWindow != null) {
-                mPastePopupWindow.hide();
-            }
+            hidePastePopupWindow();
         }
 
         public void hide() {
             mIsDragging = false;
             mContainer.dismiss();
-            if (mPastePopupWindow != null) {
-                mPastePopupWindow.hide();
-            }
+            hidePastePopupWindow();
         }
 
         public boolean isShowing() {
@@ -8868,19 +8818,15 @@
             final int compoundPaddingRight = getCompoundPaddingRight();
 
             final TextView hostView = TextView.this;
-            final int left = 0;
-            final int right = hostView.getWidth();
-            final int top = 0;
-            final int bottom = hostView.getHeight();
 
             if (mTempRect == null) {
                 mTempRect = new Rect();
             }
             final Rect clip = mTempRect;
-            clip.left = left + compoundPaddingLeft;
-            clip.top = top + extendedPaddingTop;
-            clip.right = right - compoundPaddingRight;
-            clip.bottom = bottom - extendedPaddingBottom;
+            clip.left = compoundPaddingLeft;
+            clip.top = extendedPaddingTop;
+            clip.right = hostView.getWidth() - compoundPaddingRight;
+            clip.bottom = hostView.getHeight() - extendedPaddingBottom;
 
             final ViewParent parent = hostView.getParent();
             if (parent == null || !parent.getChildVisibleRect(hostView, clip, null)) {
@@ -8892,7 +8838,8 @@
             final int posX = coords[0] + mPositionX + (int) mHotspotX;
             final int posY = coords[1] + mPositionY + (int) mHotspotY;
 
-            return posX >= clip.left && posX <= clip.right &&
+            // Offset by 1 to take into account 0.5 and int rounding around getPrimaryHorizontal.
+            return posX >= clip.left - 1 && posX <= clip.right + 1 &&
                     posY >= clip.top && posY <= clip.bottom;
         }
 
@@ -8902,23 +8849,19 @@
             if (isPositionVisible()) {
                 int[] coords = null;
                 if (mContainer.isShowing()) {
-                    coords = mTempCoords;
-                    TextView.this.getLocationInWindow(coords);
-                    final int containerPositionX = coords[0] + mPositionX;
-                    final int containerPositionY = coords[1] + mPositionY;
+                    final int containerPositionX = mPositionX;
+                    final int containerPositionY = mPositionY - TextView.this.getHeight();
 
                     if (containerPositionX != mContainerPositionX || 
                         containerPositionY != mContainerPositionY) {
                         mContainerPositionX = containerPositionX;
                         mContainerPositionY = containerPositionY;
 
-                        mContainer.update(mContainerPositionX, mContainerPositionY,
+                        mContainer.update(TextView.this, mContainerPositionX, mContainerPositionY,
                                 mRight - mLeft, mBottom - mTop);
 
                         // Hide paste popup window as soon as a scroll occurs.
-                        if (mPastePopupWindow != null) {
-                            mPastePopupWindow.hide();
-                        }
+                        hidePastePopupWindow();
                     }
                 } else {
                     show();
@@ -8936,9 +8879,7 @@
                         mLastParentY = coords[1];
                     }
                     // Hide paste popup window as soon as the handle is dragged.
-                    if (mPastePopupWindow != null) {
-                        mPastePopupWindow.hide();
-                    }
+                    hidePastePopupWindow();
                 }
             } else {
                 hide();
@@ -8985,11 +8926,16 @@
                     if (mIsInsertionHandle) {
                         long delay = SystemClock.uptimeMillis() - mTouchTimer;
                         if (delay < ViewConfiguration.getTapTimeout()) {
-                            if (mPastePopupWindow != null && mPastePopupWindow.isShowing()) {
-                                // Tapping on the handle dismisses the displayed paste view,
-                                mPastePopupWindow.hide();
-                            } else {
-                                ((InsertionPointCursorController) mController).show(0);
+                            final float deltaX = mDownPositionX - ev.getRawX();
+                            final float deltaY = mDownPositionY - ev.getRawY();
+                            final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
+                            if (distanceSquared < mSquaredTouchSlopDistance) {
+                                if (mPastePopupWindow != null && mPastePopupWindow.isShowing()) {
+                                    // Tapping on the handle dismisses the displayed paste view,
+                                    mPastePopupWindow.hide();
+                                } else {
+                                    ((InsertionPointCursorController) mController).show(0);
+                                }
                             }
                         }
                     }
@@ -9037,10 +8983,60 @@
                 mPastePopupWindow.show();
             }
         }
+
+        void hidePastePopupWindow() {
+            if (mPastePopupWindow != null) {
+                mPastePopupWindow.hide();
+            }
+        }
+
+        /**
+         * A popup window, attached to a view, and that listens to scroll events in its anchors'
+         * view hierarchy, so that it is automatically moved on such events.
+         */
+        private class ScrollingPopupWindow extends PopupWindow {
+
+            private int[] mDrawingLocations = new int[2];
+
+            public ScrollingPopupWindow(Context context, AttributeSet attrs, int defStyle) {
+                super(context, attrs, defStyle);
+            }
+
+            @Override
+            public boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
+                    int xoff, int yoff) {
+                anchor.getLocationInWindow(mDrawingLocations);
+                p.x = mDrawingLocations[0] + xoff;
+                p.y = mDrawingLocations[1] + anchor.getHeight() + yoff;
+
+                // Hide paste popup as soon as the view is scrolled.
+                hidePastePopupWindow();
+
+                if (!isPositionVisible()) {
+                    dismiss();
+                    onHandleBecomeInvisible();
+                }
+
+                return false;
+            }
+        }
+
+        public void onScrollChanged() {
+            if (isPositionVisible()) {
+                show();
+                ViewTreeObserver vto = TextView.this.getViewTreeObserver();
+                vto.removeOnScrollChangedListener(this);
+            }
+        }
+
+        public void onHandleBecomeInvisible() {
+            ViewTreeObserver vto = TextView.this.getViewTreeObserver();
+            vto.addOnScrollChangedListener(this);
+        }
     }
 
     private class InsertionPointCursorController implements CursorController {
-        private static final int DELAY_BEFORE_FADE_OUT = 4100;
+        private static final int DELAY_BEFORE_FADE_OUT = 4000;
         private static final int DELAY_BEFORE_PASTE = 2000;
         private static final int RECENT_CUT_COPY_DURATION = 15 * 1000;
 
@@ -9056,7 +9052,6 @@
         public void show(int delayBeforePaste) {
             updatePosition();
             hideDelayed();
-            getHandle().show();
             removePastePopupCallback();
             final long durationSinceCutOrCopy = SystemClock.uptimeMillis() - sLastCutOrCopyTime;
             if (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION) {
@@ -9576,9 +9571,7 @@
             mInsertionPointCursorController = new InsertionPointCursorController();
 
             final ViewTreeObserver observer = getViewTreeObserver();
-            if (observer != null) {
-                observer.addOnTouchModeChangeListener(mInsertionPointCursorController);
-            }
+            observer.addOnTouchModeChangeListener(mInsertionPointCursorController);
         }
 
         return mInsertionPointCursorController;
@@ -9593,9 +9586,7 @@
             mSelectionModifierCursorController = new SelectionModifierCursorController();
 
             final ViewTreeObserver observer = getViewTreeObserver();
-            if (observer != null) {
-                observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
-            }
+            observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
         }
 
         return mSelectionModifierCursorController;
diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp
index 980003e..0d715fd 100644
--- a/core/jni/android/graphics/Camera.cpp
+++ b/core/jni/android/graphics/Camera.cpp
@@ -45,6 +45,18 @@
     v->rotateZ(SkFloatToScalar(degrees));
 }
 
+static void Camera_rotate(JNIEnv* env, jobject obj, jfloat x, jfloat y, jfloat z) {
+    Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+    v->rotateX(SkFloatToScalar(x));
+    v->rotateY(SkFloatToScalar(y));
+    v->rotateZ(SkFloatToScalar(z));
+}
+
+static void Camera_setLocation(JNIEnv* env, jobject obj, jfloat x, jfloat y, jfloat z) {
+    Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+    v->setCameraLocation(SkFloatToScalar(x), SkFloatToScalar(y), SkFloatToScalar(z));
+}
+
 static void Camera_getMatrix(JNIEnv* env, jobject obj, int native_matrix) {
     Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
     v->getMatrix((SkMatrix*)native_matrix);
@@ -79,6 +91,8 @@
     { "rotateX",             "(F)V",   (void*)Camera_rotateX       },
     { "rotateY",             "(F)V",   (void*)Camera_rotateY       },
     { "rotateZ",             "(F)V",   (void*)Camera_rotateZ       },
+    { "rotate",              "(FFF)V", (void*)Camera_rotate        },
+    { "setLocation",         "(FFF)V", (void*)Camera_setLocation   },
     { "nativeGetMatrix",     "(I)V",   (void*)Camera_getMatrix     },
     { "nativeApplyToCanvas", "(I)V",   (void*)Camera_applyToCanvas },
     { "dotWithNormal",       "(FFF)F", (void*)Camera_dotWithNormal }
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index 147e1fa..e957635 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -23,6 +23,8 @@
 #include "unicode/ushape.h"
 #include <utils/Log.h>
 
+// Log debug messages from RTL related allocations
+#define DEBUG_RTL_ALLOCATIONS 0
 
 namespace android {
 // Returns true if we might need layout.  If bidiFlags force LTR, assume no layout, if
@@ -38,7 +40,7 @@
         return true;
     }
     for (int i = 0; i < len; ++i) {
-        if (text[i] >= 0x0590) {
+        if (text[i] >= UNICODE_FIRST_RTL_CHAR) {
             return true;
         }
     }
@@ -59,7 +61,12 @@
  */
 int TextLayout::shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount,
                         jchar* shaped, UErrorCode &status) {
-    jchar buffer[contextCount];
+    SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
+    jchar* buffer = tempBuffer.get();
+
+#if DEBUG_RTL_ALLOCATIONS
+    LOGD("TextLayout::shapeRtlText - allocated buffer with size: %d", contextCount);
+#endif
 
     // Use fixed length since we need to keep start and count valid
     u_shapeArabic(context, contextCount, buffer, contextCount,
@@ -68,10 +75,10 @@
                    U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
 
     if (U_SUCCESS(status)) {
-        // trim out 0xffff following ligatures, if any
+        // trim out UNICODE_NOT_A_CHAR following ligatures, if any
         int end = 0;
         for (int i = start, e = start + count; i < e; ++i) {
-            if (buffer[i] != 0xffff) {
+            if (buffer[i] != UNICODE_NOT_A_CHAR) {
                 buffer[end++] = buffer[i];
             }
         }
@@ -83,7 +90,6 @@
             return count;
         }
     }
-
     return -1;
 }
 
@@ -160,6 +166,11 @@
         if (!buffer) {
             return false;
         }
+
+#if DEBUG_RTL_ALLOCATIONS
+    LOGD("TextLayout::prepareText - allocated buffer with size: %d", len);
+#endif
+
         UErrorCode status = U_ZERO_ERROR;
         len = layoutLine(text, len, bidiFlags, dir, buffer, status); // might change len, dir
         if (!U_SUCCESS(status)) {
@@ -228,7 +239,7 @@
     if (U_SUCCESS(status)) {
         return true;
     } else {
-        LOG(LOG_WARN, "LAYOUT", "drawTextRun error %d\n", status);
+        LOGW("drawTextRun error %d\n", status);
     }
     return false;
 }
@@ -242,7 +253,7 @@
 
      uint8_t rtl = dirFlags & 0x1;
      if (rtl) {
-         SkAutoSTMalloc<80, jchar> buffer(contextCount);
+         SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> buffer(contextCount);
          if (prepareRtlTextRun(chars, start, count, contextCount, buffer.get())) {
              canvas->drawText(buffer.get(), count << 1, x_, y_, *paint);
          }
@@ -254,11 +265,17 @@
 void TextLayout::getTextRunAdvances(SkPaint *paint, const jchar *chars, jint start,
                                     jint count, jint contextCount, jint dirFlags,
                                     jfloat *resultAdvances, jfloat &resultTotalAdvance) {
-    jchar buffer[contextCount];
-
-    SkScalar* scalarArray = (SkScalar *)resultAdvances;
     resultTotalAdvance = 0;
 
+    SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
+    jchar* buffer = tempBuffer.get();
+
+#if DEBUG_RTL_ALLOCATIONS
+    LOGD("TextLayout::getTextRunAdvances - allocated buffer with size: %d", contextCount);
+#endif
+
+    SkScalar* scalarArray = (SkScalar*)resultAdvances;
+
     // this is where we'd call harfbuzz
     // for now we just use ushape.c
 
@@ -274,8 +291,8 @@
         // we shouldn't fail unless there's an out of memory condition,
         // in which case we're hosed anyway
         for (int i = start, e = i + count; i < e; ++i) {
-          if (buffer[i] == 0xffff) {
-            buffer[i] = 0x200b; // zero-width-space for skia
+          if (buffer[i] == UNICODE_NOT_A_CHAR) {
+            buffer[i] = UNICODE_ZWSP; // zero-width-space for skia
           }
         }
         text = buffer + start;
@@ -293,8 +310,11 @@
         // leaving the remaining widths zero.  Not nice.
         for (int i = 0, p = 0; i < widths; ++i) {
             resultTotalAdvance += resultAdvances[p++] = SkScalarToFloat(scalarArray[i]);
-            if (p < count && text[p] >= 0xdc00 && text[p] < 0xe000 &&
-                    text[p-1] >= 0xd800 && text[p-1] < 0xdc00) {
+            if (p < count &&
+                    text[p] >= UNICODE_FIRST_LOW_SURROGATE &&
+                    text[p] < UNICODE_FIRST_PRIVATE_USE &&
+                    text[p-1] >= UNICODE_FIRST_HIGH_SURROGATE &&
+                    text[p-1] < UNICODE_FIRST_LOW_SURROGATE) {
                 resultAdvances[p++] = 0;
             }
         }
@@ -331,7 +351,12 @@
         return;
     }
 
-    SkAutoSTMalloc<80, jchar> buffer(count);
+    SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> buffer(count);
+
+#if DEBUG_RTL_ALLOCATIONS
+    LOGD("TextLayout::drawTextOnPath - allocated buffer with size: %d", count);
+#endif
+
     int dir = kDirection_LTR;
     UErrorCode status = U_ZERO_ERROR;
     count = layoutLine(text, count, bidiFlags, dir, buffer.get(), status);
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index 8f666c0..c98f745 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -22,6 +22,18 @@
 
 namespace android {
 
+#define UNICODE_NOT_A_CHAR              0xffff
+#define UNICODE_ZWSP                    0x200b
+#define UNICODE_FIRST_LOW_SURROGATE     0xdc00
+#define UNICODE_FIRST_HIGH_SURROGATE    0xd800
+#define UNICODE_FIRST_PRIVATE_USE       0xe000
+#define UNICODE_FIRST_RTL_CHAR          0x0590
+
+/*
+ * Temporary buffer size
+ */
+#define CHAR_BUFFER_SIZE 80
+
 class TextLayout {
 public:
 
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 0430a81..56f2646 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -150,12 +150,12 @@
     pfd[0].events = POLLIN;
     pfd[0].revents = 0;
     pfd[1].fd = mDispatchKeyRead;
-    pfd[0].events = POLLIN;
-    pfd[0].revents = 0;
+    pfd[1].events = POLLIN;
+    pfd[1].revents = 0;
     
     int nfd = poll(pfd, 2, 0);
     if (nfd <= 0) return 0;
-    return (pfd[0].revents == POLLIN || pfd[1].revents == POLLIN) ? 1 : -1;
+    return ((pfd[0].revents & POLLIN) || (pfd[1].revents & POLLIN)) ? 1 : -1;
 }
 
 int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
diff --git a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
index bf23650..acf858a 100755
--- a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
+++ b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
@@ -89,40 +89,40 @@
 #endif
 
 static void classInitNative(JNIEnv* env, jclass clazz) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
 
     /* in */
     field_mNativeData = get_field(env, clazz, "mNativeData", "I");
-    field_mHandsfreeAgRfcommChannel = 
+    field_mHandsfreeAgRfcommChannel =
         get_field(env, clazz, "mHandsfreeAgRfcommChannel", "I");
-    field_mHeadsetAgRfcommChannel = 
+    field_mHeadsetAgRfcommChannel =
         get_field(env, clazz, "mHeadsetAgRfcommChannel", "I");
 
     /* out */
-    field_mConnectingHeadsetAddress = 
-        get_field(env, clazz, 
+    field_mConnectingHeadsetAddress =
+        get_field(env, clazz,
                   "mConnectingHeadsetAddress", "Ljava/lang/String;");
-    field_mConnectingHeadsetRfcommChannel = 
+    field_mConnectingHeadsetRfcommChannel =
         get_field(env, clazz, "mConnectingHeadsetRfcommChannel", "I");
-    field_mConnectingHeadsetSocketFd = 
+    field_mConnectingHeadsetSocketFd =
         get_field(env, clazz, "mConnectingHeadsetSocketFd", "I");
 
-    field_mConnectingHandsfreeAddress = 
-        get_field(env, clazz, 
+    field_mConnectingHandsfreeAddress =
+        get_field(env, clazz,
                   "mConnectingHandsfreeAddress", "Ljava/lang/String;");
-    field_mConnectingHandsfreeRfcommChannel = 
+    field_mConnectingHandsfreeRfcommChannel =
         get_field(env, clazz, "mConnectingHandsfreeRfcommChannel", "I");
-    field_mConnectingHandsfreeSocketFd = 
+    field_mConnectingHandsfreeSocketFd =
         get_field(env, clazz, "mConnectingHandsfreeSocketFd", "I");
 
-    field_mTimeoutRemainingMs = 
+    field_mTimeoutRemainingMs =
         get_field(env, clazz, "mTimeoutRemainingMs", "I");
 #endif
 }
 
 static void initializeNativeDataNative(JNIEnv* env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
     if (NULL == nat) {
@@ -150,7 +150,7 @@
 }
 
 static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
@@ -165,7 +165,7 @@
 static int set_nb(int sk, bool nb) {
     int flags = fcntl(sk, F_GETFL);
     if (flags < 0) {
-        LOGE("Can't get socket flags with fcntl(): %s (%d)", 
+        LOGE("Can't get socket flags with fcntl(): %s (%d)",
              strerror(errno), errno);
         close(sk);
         return -1;
@@ -255,7 +255,7 @@
 
 static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
                                               jint timeout_ms) {
-//    LOGV(__FUNCTION__);
+//    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
 
     env->SetIntField(object, field_mTimeoutRemainingMs, timeout_ms);
@@ -264,11 +264,11 @@
     native_data_t *nat = get_native_data(env, object);
 #if USE_ACCEPT_DIRECTLY
     if (nat->hf_ag_rfcomm_channel > 0) {
-        LOGI("Setting HF AG server socket to RFCOMM port %d!", 
+        LOGI("Setting HF AG server socket to RFCOMM port %d!",
              nat->hf_ag_rfcomm_channel);
         struct timeval tv;
         int len = sizeof(tv);
-        if (getsockopt(nat->hf_ag_rfcomm_channel, 
+        if (getsockopt(nat->hf_ag_rfcomm_channel,
                        SOL_SOCKET, SO_RCVTIMEO, &tv, &len) < 0) {
             LOGE("getsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
                  nat->hf_ag_rfcomm_channel,
@@ -276,12 +276,12 @@
                  errno);
             return JNI_FALSE;
         }
-        LOGI("Current HF AG server socket RCVTIMEO is (%d(s), %d(us))!", 
+        LOGI("Current HF AG server socket RCVTIMEO is (%d(s), %d(us))!",
              (int)tv.tv_sec, (int)tv.tv_usec);
         if (timeout_ms >= 0) {
             tv.tv_sec = timeout_ms / 1000;
             tv.tv_usec = 1000 * (timeout_ms % 1000);
-            if (setsockopt(nat->hf_ag_rfcomm_channel, 
+            if (setsockopt(nat->hf_ag_rfcomm_channel,
                            SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
                 LOGE("setsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
                      nat->hf_ag_rfcomm_channel,
@@ -289,11 +289,11 @@
                      errno);
                 return JNI_FALSE;
             }
-            LOGI("Changed HF AG server socket RCVTIMEO to (%d(s), %d(us))!", 
+            LOGI("Changed HF AG server socket RCVTIMEO to (%d(s), %d(us))!",
                  (int)tv.tv_sec, (int)tv.tv_usec);
         }
 
-        if (!do_accept(env, object, nat->hf_ag_rfcomm_sock, 
+        if (!do_accept(env, object, nat->hf_ag_rfcomm_sock,
                        field_mConnectingHandsfreeSocketFd,
                        field_mConnectingHandsfreeAddress,
                        field_mConnectingHandsfreeRfcommChannel))
@@ -309,13 +309,13 @@
     FD_ZERO(&rset);
     int cnt = 0;
     if (nat->hf_ag_rfcomm_channel > 0) {
-        LOGI("Setting HF AG server socket to RFCOMM port %d!", 
+        LOGI("Setting HF AG server socket to RFCOMM port %d!",
              nat->hf_ag_rfcomm_channel);
         cnt++;
         FD_SET(nat->hf_ag_rfcomm_sock, &rset);
     }
     if (nat->hs_ag_rfcomm_channel > 0) {
-        LOGI("Setting HS AG server socket to RFCOMM port %d!", 
+        LOGI("Setting HS AG server socket to RFCOMM port %d!",
              nat->hs_ag_rfcomm_channel);
         cnt++;
         FD_SET(nat->hs_ag_rfcomm_sock, &rset);
@@ -330,7 +330,7 @@
         to.tv_sec = timeout_ms / 1000;
         to.tv_usec = 1000 * (timeout_ms % 1000);
     }
-    n = select(MAX(nat->hf_ag_rfcomm_sock, 
+    n = select(MAX(nat->hf_ag_rfcomm_sock,
                        nat->hs_ag_rfcomm_sock) + 1,
                    &rset,
                    NULL,
@@ -354,7 +354,7 @@
         return JNI_FALSE;
     }
 
-    n = on_accept_set_fields(env, object, 
+    n = on_accept_set_fields(env, object,
                              &rset, nat->hf_ag_rfcomm_sock,
                              field_mConnectingHandsfreeSocketFd,
                              field_mConnectingHandsfreeAddress,
@@ -371,7 +371,7 @@
     struct pollfd fds[2];
     int cnt = 0;
     if (nat->hf_ag_rfcomm_channel > 0) {
-//        LOGI("Setting HF AG server socket %d to RFCOMM port %d!", 
+//        LOGI("Setting HF AG server socket %d to RFCOMM port %d!",
 //             nat->hf_ag_rfcomm_sock,
 //             nat->hf_ag_rfcomm_channel);
         fds[cnt].fd = nat->hf_ag_rfcomm_sock;
@@ -379,7 +379,7 @@
         cnt++;
     }
     if (nat->hs_ag_rfcomm_channel > 0) {
-//        LOGI("Setting HS AG server socket %d to RFCOMM port %d!", 
+//        LOGI("Setting HS AG server socket %d to RFCOMM port %d!",
 //             nat->hs_ag_rfcomm_sock,
 //             nat->hs_ag_rfcomm_channel);
         fds[cnt].fd = nat->hs_ag_rfcomm_sock;
@@ -411,7 +411,7 @@
         if (fds[cnt].fd == nat->hf_ag_rfcomm_sock) {
             if (fds[cnt].revents & (POLLIN | POLLPRI | POLLOUT)) {
                 LOGI("Accepting HF connection.\n");
-                err += do_accept(env, object, fds[cnt].fd, 
+                err += do_accept(env, object, fds[cnt].fd,
                                field_mConnectingHandsfreeSocketFd,
                                field_mConnectingHandsfreeAddress,
                                field_mConnectingHandsfreeRfcommChannel);
@@ -421,7 +421,7 @@
         else if (fds[cnt].fd == nat->hs_ag_rfcomm_sock) {
             if (fds[cnt].revents & (POLLIN | POLLPRI | POLLOUT)) {
                 LOGI("Accepting HS connection.\n");
-                err += do_accept(env, object, fds[cnt].fd, 
+                err += do_accept(env, object, fds[cnt].fd,
                                field_mConnectingHeadsetSocketFd,
                                field_mConnectingHeadsetAddress,
                                field_mConnectingHeadsetRfcommChannel);
@@ -444,7 +444,7 @@
 }
 
 static jboolean setUpListeningSocketsNative(JNIEnv* env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
 
@@ -509,7 +509,7 @@
     private native void tearDownListeningSocketsNative();
 */
 static void tearDownListeningSocketsNative(JNIEnv *env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
 
diff --git a/core/jni/android_bluetooth_BluetoothSocket.cpp b/core/jni/android_bluetooth_BluetoothSocket.cpp
index 31ebf8c..b87f7c4 100644
--- a/core/jni/android_bluetooth_BluetoothSocket.cpp
+++ b/core/jni/android_bluetooth_BluetoothSocket.cpp
@@ -66,7 +66,7 @@
 
 static void initSocketFromFdNative(JNIEnv *env, jobject obj, jint fd) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     struct asocket *s = asocket_init(fd);
 
@@ -85,7 +85,7 @@
 
 static void initSocketNative(JNIEnv *env, jobject obj) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     int fd;
     int lm = 0;
@@ -161,7 +161,7 @@
 
 static void connectNative(JNIEnv *env, jobject obj) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     int ret;
     jint type;
@@ -240,7 +240,7 @@
 /* Returns errno instead of throwing, so java can check errno */
 static int bindListenNative(JNIEnv *env, jobject obj) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     jint type;
     socklen_t addr_sz;
@@ -307,7 +307,7 @@
 
 static jobject acceptNative(JNIEnv *env, jobject obj, int timeout) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     int fd;
     jint type;
@@ -380,7 +380,7 @@
 
 static jint availableNative(JNIEnv *env, jobject obj) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     int available;
     struct asocket *s = get_socketData(env, obj);
@@ -403,7 +403,7 @@
 static jint readNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
         jint length) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     int ret;
     jbyte *b;
@@ -446,7 +446,7 @@
 static jint writeNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
         jint length) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     int ret;
     jbyte *b;
@@ -488,7 +488,7 @@
 
 static void abortNative(JNIEnv *env, jobject obj) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     struct asocket *s = get_socketData(env, obj);
 
     if (!s)
@@ -504,7 +504,7 @@
 
 static void destroyNative(JNIEnv *env, jobject obj) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     struct asocket *s = get_socketData(env, obj);
     int fd = s->fd;
 
diff --git a/core/jni/android_bluetooth_HeadsetBase.cpp b/core/jni/android_bluetooth_HeadsetBase.cpp
index 4e9fbaf..bbf1ae5 100644
--- a/core/jni/android_bluetooth_HeadsetBase.cpp
+++ b/core/jni/android_bluetooth_HeadsetBase.cpp
@@ -180,7 +180,7 @@
 #endif
 
 static void classInitNative(JNIEnv* env, jclass clazz) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     field_mNativeData = get_field(env, clazz, "mNativeData", "I");
     field_mAddress = get_field(env, clazz, "mAddress", "Ljava/lang/String;");
@@ -191,7 +191,7 @@
 
 static void initializeNativeDataNative(JNIEnv* env, jobject object,
                                        jint socketFd) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
     if (NULL == nat) {
@@ -213,7 +213,7 @@
 }
 
 static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat =
         (native_data_t *)env->GetIntField(object, field_mNativeData);
@@ -226,7 +226,7 @@
 
 static jboolean connectNative(JNIEnv *env, jobject obj)
 {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     int lm;
     struct sockaddr_rc addr;
@@ -278,7 +278,7 @@
 }
 
 static jint connectAsyncNative(JNIEnv *env, jobject obj) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     struct sockaddr_rc addr;
     native_data_t *nat = get_native_data(env, obj);
@@ -357,7 +357,7 @@
 
 static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj,
                                            jint timeout_ms) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     struct sockaddr_rc addr;
     native_data_t *nat = get_native_data(env, obj);
@@ -463,7 +463,7 @@
 }
 
 static void disconnectNative(JNIEnv *env, jobject obj) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, obj);
     if (nat->rfcomm_sock >= 0) {
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 9f70509..bfbfd37 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -53,25 +53,48 @@
     virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
     virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr);
     virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
-    void addCallbackBuffer(JNIEnv *env, jbyteArray cbb);
+    void addCallbackBuffer(JNIEnv *env, jbyteArray cbb, int msgType);
     void setCallbackMode(JNIEnv *env, bool installed, bool manualMode);
     sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; }
+    bool isRawImageCallbackBufferAvailable() const;
     void release();
 
 private:
     void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType);
+    void clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers);
     void clearCallbackBuffers_l(JNIEnv *env);
+    jbyteArray getCallbackBuffer(JNIEnv *env, Vector<jbyteArray> *buffers, size_t bufferSize);
 
     jobject     mCameraJObjectWeak;     // weak reference to java object
     jclass      mCameraJClass;          // strong reference to java class
     sp<Camera>  mCamera;                // strong reference to native object
     Mutex       mLock;
 
+    /*
+     * Global reference application-managed raw image buffer queue.
+     *
+     * Manual-only mode is supported for raw image callbacks, which is
+     * set whenever method addCallbackBuffer() with msgType =
+     * CAMERA_MSG_RAW_IMAGE is called; otherwise, null is returned
+     * with raw image callbacks.
+     */
+    Vector<jbyteArray> mRawImageCallbackBuffers;
+
+    /*
+     * Application-managed preview buffer queue and the flags
+     * associated with the usage of the preview buffer callback.
+     */
     Vector<jbyteArray> mCallbackBuffers; // Global reference application managed byte[]
     bool mManualBufferMode;              // Whether to use application managed buffers.
-    bool mManualCameraCallbackSet;       // Whether the callback has been set, used to reduce unnecessary calls to set the callback.
+    bool mManualCameraCallbackSet;       // Whether the callback has been set, used to
+                                         // reduce unnecessary calls to set the callback.
 };
 
+bool JNICameraContext::isRawImageCallbackBufferAvailable() const
+{
+    return !mRawImageCallbackBuffers.isEmpty();
+}
+
 sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext)
 {
     sp<Camera> camera;
@@ -128,10 +151,48 @@
         return;
     }
     JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    /*
+     * If the notification or msgType is CAMERA_MSG_RAW_IMAGE_NOTIFY, change it
+     * to CAMERA_MSG_RAW_IMAGE since CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed
+     * to the Java app.
+     */
+    if (msgType == CAMERA_MSG_RAW_IMAGE_NOTIFY) {
+        msgType = CAMERA_MSG_RAW_IMAGE;
+    }
+
     env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
             mCameraJObjectWeak, msgType, ext1, ext2, NULL);
 }
 
+jbyteArray JNICameraContext::getCallbackBuffer(
+        JNIEnv* env, Vector<jbyteArray>* buffers, size_t bufferSize)
+{
+    jbyteArray obj = NULL;
+
+    // Vector access should be protected by lock in postData()
+    if (!buffers->isEmpty()) {
+        LOGV("Using callback buffer from queue of length %d", buffers->size());
+        jbyteArray globalBuffer = buffers->itemAt(0);
+        buffers->removeAt(0);
+
+        obj = (jbyteArray)env->NewLocalRef(globalBuffer);
+        env->DeleteGlobalRef(globalBuffer);
+
+        if (obj != NULL) {
+            jsize bufferLength = env->GetArrayLength(obj);
+            if ((int)bufferLength < (int)bufferSize) {
+                LOGE("Callback buffer was too small! Expected %d bytes, but got %d bytes!",
+                    bufferSize, bufferLength);
+                env->DeleteLocalRef(obj);
+                return NULL;
+            }
+        }
+    }
+
+    return obj;
+}
+
 void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType)
 {
     jbyteArray obj = NULL;
@@ -141,7 +202,7 @@
         ssize_t offset;
         size_t size;
         sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size);
-        LOGV("postData: off=%d, size=%d", offset, size);
+        LOGV("copyAndPost: off=%ld, size=%d", offset, size);
         uint8_t *heapBase = (uint8_t*)heap->base();
 
         if (heapBase != NULL) {
@@ -151,32 +212,28 @@
                 LOGV("Allocating callback buffer");
                 obj = env->NewByteArray(size);
             } else {
-                // Vector access should be protected by lock in postData()
-                if(!mCallbackBuffers.isEmpty()) {
-                    LOGV("Using callback buffer from queue of length %d", mCallbackBuffers.size());
-                    jbyteArray globalBuffer = mCallbackBuffers.itemAt(0);
-                    mCallbackBuffers.removeAt(0);
+                switch (msgType) {
+                    case CAMERA_MSG_PREVIEW_FRAME: {
+                        obj = getCallbackBuffer(env, &mCallbackBuffers, size);
 
-                    obj = (jbyteArray)env->NewLocalRef(globalBuffer);
-                    env->DeleteGlobalRef(globalBuffer);
+                        if (mCallbackBuffers.isEmpty()) {
+                            LOGV("Out of buffers, clearing callback!");
+                            mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
+                            mManualCameraCallbackSet = false;
 
-                    if (obj != NULL) {
-                        jsize bufferLength = env->GetArrayLength(obj);
-                        if ((int)bufferLength < (int)size) {
-                            LOGE("Manually set buffer was too small! Expected %d bytes, but got %d!",
-                                 size, bufferLength);
-                            env->DeleteLocalRef(obj);
-                            return;
+                            if (obj == NULL) {
+                                return;
+                            }
                         }
+                        break;
                     }
-                }
-
-                if(mCallbackBuffers.isEmpty()) {
-                    LOGV("Out of buffers, clearing callback!");
-                    mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
-                    mManualCameraCallbackSet = false;
-
-                    if (obj == NULL) {
+                    case CAMERA_MSG_RAW_IMAGE: {
+                        obj = getCallbackBuffer(env, &mRawImageCallbackBuffers, size);
+                        break;
+                    }
+                    default: {
+                        jniThrowException(env,
+                            "java/lang/RuntimeException", "Unsupported message type");
                         return;
                     }
                 }
@@ -212,21 +269,27 @@
     }
 
     // return data based on callback type
-    switch(msgType) {
-    case CAMERA_MSG_VIDEO_FRAME:
-        // should never happen
-        break;
-    // don't return raw data to Java
-    case CAMERA_MSG_RAW_IMAGE:
-        LOGV("rawCallback");
-        env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
-                mCameraJObjectWeak, msgType, 0, 0, NULL);
-        break;
-    default:
-        // TODO: Change to LOGV
-        LOGV("dataCallback(%d, %p)", msgType, dataPtr.get());
-        copyAndPost(env, dataPtr, msgType);
-        break;
+    switch (msgType) {
+        case CAMERA_MSG_VIDEO_FRAME:
+            // should never happen
+            break;
+
+        // For backward-compatibility purpose, if there is no callback
+        // buffer for raw image, the callback returns null.
+        case CAMERA_MSG_RAW_IMAGE:
+            LOGV("rawCallback");
+            if (mRawImageCallbackBuffers.isEmpty()) {
+                env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
+                        mCameraJObjectWeak, msgType, 0, 0, NULL);
+            } else {
+                copyAndPost(env, dataPtr, msgType);
+            }
+            break;
+
+        default:
+            LOGV("dataCallback(%d, %p)", msgType, dataPtr.get());
+            copyAndPost(env, dataPtr, msgType);
+            break;
     }
 }
 
@@ -251,7 +314,7 @@
 
     if (!installed) {
         mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
-        clearCallbackBuffers_l(env);
+        clearCallbackBuffers_l(env, &mCallbackBuffers);
     } else if (mManualBufferMode) {
         if (!mCallbackBuffers.isEmpty()) {
             mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA);
@@ -259,24 +322,44 @@
         }
     } else {
         mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_BARCODE_SCANNER);
-        clearCallbackBuffers_l(env);
+        clearCallbackBuffers_l(env, &mCallbackBuffers);
     }
 }
 
-void JNICameraContext::addCallbackBuffer(JNIEnv *env, jbyteArray cbb)
+void JNICameraContext::addCallbackBuffer(
+        JNIEnv *env, jbyteArray cbb, int msgType)
 {
+    LOGV("addCallbackBuffer: 0x%x", msgType);
     if (cbb != NULL) {
         Mutex::Autolock _l(mLock);
-        jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb);
-        mCallbackBuffers.push(cbb);
+        switch (msgType) {
+            case CAMERA_MSG_PREVIEW_FRAME: {
+                jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb);
+                mCallbackBuffers.push(callbackBuffer);
 
-        LOGV("Adding callback buffer to queue, %d total", mCallbackBuffers.size());
+                LOGV("Adding callback buffer to queue, %d total",
+                        mCallbackBuffers.size());
 
-        // We want to make sure the camera knows we're ready for the next frame.
-        // This may have come unset had we not had a callbackbuffer ready for it last time.
-        if (mManualBufferMode && !mManualCameraCallbackSet) {
-            mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA);
-            mManualCameraCallbackSet = true;
+                // We want to make sure the camera knows we're ready for the
+                // next frame. This may have come unset had we not had a
+                // callbackbuffer ready for it last time.
+                if (mManualBufferMode && !mManualCameraCallbackSet) {
+                    mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA);
+                    mManualCameraCallbackSet = true;
+                }
+                break;
+            }
+            case CAMERA_MSG_RAW_IMAGE: {
+                jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb);
+                mRawImageCallbackBuffers.push(callbackBuffer);
+                break;
+            }
+            default: {
+                jniThrowException(env,
+                        "java/lang/IllegalArgumentException",
+                        "Unsupported message type");
+                return;
+            }
         }
     } else {
        LOGE("Null byte array!");
@@ -285,10 +368,15 @@
 
 void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env)
 {
-    LOGV("Clearing callback buffers, %d remained", mCallbackBuffers.size());
-    while(!mCallbackBuffers.isEmpty()) {
-        env->DeleteGlobalRef(mCallbackBuffers.top());
-        mCallbackBuffers.pop();
+    clearCallbackBuffers_l(env, &mCallbackBuffers);
+    clearCallbackBuffers_l(env, &mRawImageCallbackBuffers);
+}
+
+void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers) {
+    LOGV("Clearing callback buffers, %d remained", buffers->size());
+    while (!buffers->isEmpty()) {
+        env->DeleteGlobalRef(buffers->top());
+        buffers->pop();
     }
 }
 
@@ -458,13 +546,13 @@
     context->setCallbackMode(env, installed, manualBuffer);
 }
 
-static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes) {
-    LOGV("addCallbackBuffer");
+static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes, int msgType) {
+    LOGV("addCallbackBuffer: 0x%x", msgType);
 
     JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context));
 
     if (context != NULL) {
-        context->addCallbackBuffer(env, bytes);
+        context->addCallbackBuffer(env, bytes, msgType);
     }
 }
 
@@ -492,14 +580,32 @@
     }
 }
 
-static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz)
+static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz, int msgType)
 {
     LOGV("takePicture");
     JNICameraContext* context;
     sp<Camera> camera = get_native_camera(env, thiz, &context);
     if (camera == 0) return;
 
-    if (camera->takePicture() != NO_ERROR) {
+    /*
+     * When CAMERA_MSG_RAW_IMAGE is requested, if the raw image callback
+     * buffer is available, CAMERA_MSG_RAW_IMAGE is enabled to get the
+     * notification _and_ the data; otherwise, CAMERA_MSG_RAW_IMAGE_NOTIFY
+     * is enabled to receive the callback notification but no data.
+     *
+     * Note that CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed to the
+     * Java application.
+     */
+    if (msgType & CAMERA_MSG_RAW_IMAGE) {
+        LOGV("Enable raw image callback buffer");
+        if (!context->isRawImageCallbackBufferAvailable()) {
+            LOGV("Enable raw image notification, since no callback buffer exists");
+            msgType &= ~CAMERA_MSG_RAW_IMAGE;
+            msgType |= CAMERA_MSG_RAW_IMAGE_NOTIFY;
+        }
+    }
+
+    if (camera->takePicture(msgType) != NO_ERROR) {
         jniThrowException(env, "java/lang/RuntimeException", "takePicture failed");
         return;
     }
@@ -638,8 +744,8 @@
   { "setHasPreviewCallback",
     "(ZZ)V",
     (void *)android_hardware_Camera_setHasPreviewCallback },
-  { "addCallbackBuffer",
-    "([B)V",
+  { "_addCallbackBuffer",
+    "([BI)V",
     (void *)android_hardware_Camera_addCallbackBuffer },
   { "native_autoFocus",
     "()V",
@@ -648,7 +754,7 @@
     "()V",
     (void *)android_hardware_Camera_cancelAutoFocus },
   { "native_takePicture",
-    "()V",
+    "(I)V",
     (void *)android_hardware_Camera_takePicture },
   { "native_setParameters",
     "(Ljava/lang/String;)V",
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index fc806a5..667ba75 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -556,6 +556,18 @@
     return doBooleanCommand(cmdstr, "OK");
 }
 
+static void android_net_wifi_enableBackgroundScan(JNIEnv* env, jobject clazz, jboolean enable)
+{
+    //Note: BGSCAN-START and BGSCAN-STOP are documented in core/res/res/values/config.xml
+    //and will need an update if the names are changed
+    if (enable) {
+        doBooleanCommand("DRIVER BGSCAN-START", "OK");
+    }
+    else {
+        doBooleanCommand("DRIVER BGSCAN-STOP", "OK");
+    }
+}
+
 // ----------------------------------------------------------------------------
 
 /*
@@ -623,6 +635,7 @@
         (void*) android_net_wifi_setSuspendOptimizationsCommand},
     { "setCountryCodeCommand", "(Ljava/lang/String;)Z",
         (void*) android_net_wifi_setCountryCodeCommand},
+    { "enableBackgroundScan", "(Z)V", (void*) android_net_wifi_enableBackgroundScan},
 };
 
 int register_android_net_wifi_WifiManager(JNIEnv* env)
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
index 8c795af..1851ad6 100644
--- a/core/jni/android_server_BluetoothA2dpService.cpp
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -61,7 +61,7 @@
  * Return false if dbus is down, or another serious error (out of memory)
 */
 static bool initNative(JNIEnv* env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     nat = (native_data_t *)calloc(1, sizeof(native_data_t));
     if (NULL == nat) {
@@ -88,7 +88,7 @@
 
 static void cleanupNative(JNIEnv* env, jobject object) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     if (nat) {
         dbus_connection_close(nat->conn);
         env->DeleteGlobalRef(nat->me);
@@ -101,7 +101,7 @@
 static jobjectArray getSinkPropertiesNative(JNIEnv *env, jobject object,
                                             jstring path) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     if (nat) {
         DBusMessage *msg, *reply;
         DBusError err;
@@ -132,7 +132,7 @@
 
 static jboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     if (nat) {
         const char *c_path = env->GetStringUTFChars(path, NULL);
         int len = env->GetStringLength(path) + 1;
@@ -153,7 +153,7 @@
 static jboolean disconnectSinkNative(JNIEnv *env, jobject object,
                                      jstring path) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     if (nat) {
         const char *c_path = env->GetStringUTFChars(path, NULL);
 
@@ -171,7 +171,7 @@
 static jboolean suspendSinkNative(JNIEnv *env, jobject object,
                                      jstring path) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     if (nat) {
         const char *c_path = env->GetStringUTFChars(path, NULL);
         bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
@@ -187,7 +187,7 @@
 static jboolean resumeSinkNative(JNIEnv *env, jobject object,
                                      jstring path) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     if (nat) {
         const char *c_path = env->GetStringUTFChars(path, NULL);
         bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
@@ -203,7 +203,7 @@
 static jboolean avrcpVolumeUpNative(JNIEnv *env, jobject object,
                                      jstring path) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     if (nat) {
         const char *c_path = env->GetStringUTFChars(path, NULL);
         bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
@@ -219,7 +219,7 @@
 static jboolean avrcpVolumeDownNative(JNIEnv *env, jobject object,
                                      jstring path) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     if (nat) {
         const char *c_path = env->GetStringUTFChars(path, NULL);
         bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
@@ -278,7 +278,7 @@
 }
 
 void onConnectSinkResult(DBusMessage *msg, void *user, void *n) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     native_data_t *nat = (native_data_t *)n;
     const char *path = (const char *)user;
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index fd12c2d7..afaade8 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -88,7 +88,7 @@
 
 #endif
 static void classInitNative(JNIEnv* env, jclass clazz) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
 #ifdef HAVE_BLUETOOTH
     method_onPropertyChanged = env->GetMethodID(clazz, "onPropertyChanged",
@@ -147,7 +147,7 @@
 }
 
 static void initializeNativeDataNative(JNIEnv* env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
     if (NULL == nat) {
@@ -175,7 +175,7 @@
 }
 
 static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat =
             (native_data_t *)env->GetIntField(object, field_mNativeData);
@@ -216,7 +216,7 @@
 }
 
 static jboolean setUpEventLoop(native_data_t *nat) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     if (nat != NULL && nat->conn != NULL) {
         dbus_threads_init_default();
@@ -395,7 +395,7 @@
 }
 
 static void tearDownEventLoop(native_data_t *nat) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     if (nat != NULL && nat->conn != NULL) {
 
         DBusMessage *msg, *reply;
@@ -1229,7 +1229,7 @@
 #ifdef HAVE_BLUETOOTH
 
 void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     native_data_t *nat = (native_data_t *)n;
     const char *address = (const char *)user;
@@ -1298,7 +1298,7 @@
 }
 
 void onCreateDeviceResult(DBusMessage *msg, void *user, void *n) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     native_data_t *nat = (native_data_t *)n;
     const char *address= (const char *)user;
@@ -1328,7 +1328,7 @@
 }
 
 void onDiscoverServicesResult(DBusMessage *msg, void *user, void *n) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     native_data_t *nat = (native_data_t *)n;
     const char *path = (const char *)user;
@@ -1354,7 +1354,7 @@
 }
 
 void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     const char *address = (const char *) user;
     native_data_t *nat = (native_data_t *) n;
@@ -1387,7 +1387,7 @@
 }
 
 void onInputDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     native_data_t *nat = (native_data_t *)n;
     const char *path = (const char *)user;
@@ -1426,7 +1426,7 @@
 }
 
 void onPanDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 
     native_data_t *nat = (native_data_t *)n;
     const char *path = (const char *)user;
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
index bf0504f..158e475 100644
--- a/core/jni/android_server_BluetoothService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -1,16 +1,16 @@
 /*
 ** 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -93,7 +93,7 @@
 #endif
 
 static void classInitNative(JNIEnv* env, jclass clazz) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     field_mNativeData = get_field(env, clazz, "mNativeData", "I");
     field_mEventLoop = get_field(env, clazz, "mEventLoop",
@@ -105,7 +105,7 @@
  * Return false if dbus is down, or another serious error (out of memory)
 */
 static bool initializeNativeDataNative(JNIEnv* env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
     if (NULL == nat) {
@@ -144,7 +144,7 @@
 
 // This function is called when the adapter is enabled.
 static jboolean setupNativeDataNative(JNIEnv* env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat =
         (native_data_t *)env->GetIntField(object, field_mNativeData);
@@ -167,7 +167,7 @@
 }
 
 static jboolean tearDownNativeDataNative(JNIEnv *env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat =
                (native_data_t *)env->GetIntField(object, field_mNativeData);
@@ -181,7 +181,7 @@
 }
 
 static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat =
         (native_data_t *)env->GetIntField(object, field_mNativeData);
@@ -193,7 +193,7 @@
 }
 
 static jstring getAdapterPathNative(JNIEnv *env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
@@ -205,7 +205,7 @@
 
 
 static jboolean startDiscoveryNative(JNIEnv *env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     DBusMessage *msg = NULL;
     DBusMessage *reply = NULL;
@@ -251,7 +251,7 @@
 }
 
 static void stopDiscoveryNative(JNIEnv *env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     DBusMessage *msg = NULL;
     DBusMessage *reply = NULL;
@@ -297,7 +297,7 @@
 }
 
 static jbyteArray readAdapterOutOfBandDataNative(JNIEnv *env, jobject object) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     DBusError err;
@@ -338,7 +338,7 @@
 
 static jboolean createPairedDeviceNative(JNIEnv *env, jobject object,
                                          jstring address, jint timeout_ms) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
@@ -374,7 +374,7 @@
 
 static jboolean createPairedDeviceOutOfBandNative(JNIEnv *env, jobject object,
                                                 jstring address, jint timeout_ms) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
@@ -411,7 +411,7 @@
                                           jstring path,
                                           jstring pattern, jint attr_id) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     native_data_t *nat = get_native_data(env, object);
     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
     struct event_loop_native_data_t *eventLoopNat =
@@ -437,7 +437,7 @@
 
 static jboolean cancelDeviceCreationNative(JNIEnv *env, jobject object,
                                            jstring address) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     jboolean result = JNI_FALSE;
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
@@ -469,7 +469,7 @@
 }
 
 static jboolean removeDeviceNative(JNIEnv *env, jobject object, jstring object_path) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
@@ -492,7 +492,7 @@
 
 static jint enableNative(JNIEnv *env, jobject object) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     return bt_enable();
 #endif
     return -1;
@@ -500,7 +500,7 @@
 
 static jint disableNative(JNIEnv *env, jobject object) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     return bt_disable();
 #endif
     return -1;
@@ -508,7 +508,7 @@
 
 static jint isEnabledNative(JNIEnv *env, jobject object) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     return bt_is_enabled();
 #endif
     return -1;
@@ -518,7 +518,7 @@
                                              jstring address, bool confirm,
                                              int nativeData) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
         DBusMessage *msg = (DBusMessage *)nativeData;
@@ -549,7 +549,7 @@
 static jboolean setPasskeyNative(JNIEnv *env, jobject object, jstring address,
                          int passkey, int nativeData) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
         DBusMessage *msg = (DBusMessage *)nativeData;
@@ -576,7 +576,7 @@
 static jboolean setRemoteOutOfBandDataNative(JNIEnv *env, jobject object, jstring address,
                          jbyteArray hash, jbyteArray randomizer, int nativeData) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
         DBusMessage *msg = (DBusMessage *)nativeData;
@@ -610,7 +610,7 @@
 static jboolean setPinNative(JNIEnv *env, jobject object, jstring address,
                          jstring pin, int nativeData) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
         DBusMessage *msg = (DBusMessage *)nativeData;
@@ -640,7 +640,7 @@
 static jboolean cancelPairingUserInputNative(JNIEnv *env, jobject object,
                                             jstring address, int nativeData) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
         DBusMessage *msg = (DBusMessage *)nativeData;
@@ -666,7 +666,7 @@
                                                     jstring path)
 {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
         DBusMessage *msg, *reply;
@@ -705,7 +705,7 @@
 
 static jobjectArray getAdapterPropertiesNative(JNIEnv *env, jobject object) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
         DBusMessage *msg, *reply;
@@ -741,7 +741,7 @@
 static jboolean setAdapterPropertyNative(JNIEnv *env, jobject object, jstring key,
                                          void *value, jint type) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
         DBusMessage *msg;
@@ -808,7 +808,7 @@
 static jboolean setDevicePropertyNative(JNIEnv *env, jobject object, jstring path,
                                                jstring key, void *value, jint type) {
 #ifdef HAVE_BLUETOOTH
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
         DBusMessage *reply, *msg;
@@ -863,7 +863,7 @@
 
 static jboolean createDeviceNative(JNIEnv *env, jobject object,
                                                 jstring address) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
@@ -894,7 +894,7 @@
 
 static jboolean discoverServicesNative(JNIEnv *env, jobject object,
                                                jstring path, jstring pattern) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
@@ -955,7 +955,7 @@
 
 static jintArray addReservedServiceRecordsNative(JNIEnv *env, jobject object,
                                                 jintArray uuids) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     DBusMessage *reply = NULL;
 
@@ -979,7 +979,7 @@
 
 static jboolean removeReservedServiceRecordsNative(JNIEnv *env, jobject object,
                                                    jintArray handles) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     jint *values = env->GetIntArrayElements(handles, NULL);
@@ -1002,7 +1002,7 @@
 
 static jint addRfcommServiceRecordNative(JNIEnv *env, jobject object,
         jstring name, jlong uuidMsb, jlong uuidLsb, jshort channel) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
@@ -1027,7 +1027,7 @@
 }
 
 static jboolean removeServiceRecordNative(JNIEnv *env, jobject object, jint handle) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
@@ -1045,7 +1045,7 @@
 
 static jboolean setLinkTimeoutNative(JNIEnv *env, jobject object, jstring object_path,
                                      jint num_slots) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
@@ -1064,7 +1064,7 @@
 }
 
 static jboolean connectInputDeviceNative(JNIEnv *env, jobject object, jstring path) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
@@ -1092,7 +1092,7 @@
 
 static jboolean disconnectInputDeviceNative(JNIEnv *env, jobject object,
                                      jstring path) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
@@ -1120,7 +1120,7 @@
 
 static jboolean setBluetoothTetheringNative(JNIEnv *env, jobject object, jboolean value,
                                             jstring src_role, jstring bridge) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
@@ -1155,7 +1155,7 @@
 
 static jboolean connectPanDeviceNative(JNIEnv *env, jobject object, jstring path,
                                        jstring dstRole) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     LOGE("connectPanDeviceNative");
     native_data_t *nat = get_native_data(env, object);
@@ -1187,7 +1187,7 @@
 
 static jboolean disconnectPanDeviceNative(JNIEnv *env, jobject object,
                                      jstring path) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     LOGE("disconnectPanDeviceNative");
     native_data_t *nat = get_native_data(env, object);
@@ -1217,7 +1217,7 @@
 static jboolean disconnectPanServerDeviceNative(JNIEnv *env, jobject object,
                                                 jstring path, jstring address,
                                                 jstring iface) {
-    LOGV(__FUNCTION__);
+    LOGV("%s", __FUNCTION__);
 #ifdef HAVE_BLUETOOTH
     LOGE("disconnectPanServerDeviceNative");
     native_data_t *nat = get_native_data(env, object);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1df6fe5..12d7afd 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1196,7 +1196,7 @@
     <permission android:name="android.permission.PACKAGE_USAGE_STATS"
         android:label="@string/permlab_pkgUsageStats"
         android:description="@string/permdesc_pkgUsageStats"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signatureOrSystem" />
 
     <!-- Allows an application to collect battery statistics -->
     <permission android:name="android.permission.BATTERY_STATS"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6f37dc0..b48adf1 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2256,18 +2256,29 @@
         <attr name="unselectedAlpha" format="float" />
     </declare-styleable>
     <declare-styleable name="GridView">
+        <!-- Defines the default horizontal spacing between columns. -->
         <attr name="horizontalSpacing" format="dimension" />
+        <!-- Defines the default vertical spacing between rows. -->
         <attr name="verticalSpacing" format="dimension" />
+        <!-- Defines how columns should stretch to fill the available empty space, if any. -->
         <attr name="stretchMode">
+            <!-- Stretching is disabled. -->
             <enum name="none" value="0"/>
+            <!-- The spacing between each column is stretched. -->
             <enum name="spacingWidth" value="1" />
+            <!-- Each column is stretched equally. -->
             <enum name="columnWidth" value="2" />
+            <!-- The spacing between each column is uniformly stretched.. -->
             <enum name="spacingWidthUniform" value="3" />
         </attr>
+        <!-- Specifies the fixed width for each column. -->
         <attr name="columnWidth" format="dimension" />
+        <!-- Defines how many columns to show. -->
         <attr name="numColumns" format="integer" min="0">
+            <!-- Display as many columns as possible to fill the available space. -->
             <enum name="auto_fit" value="-1" />
         </attr>
+        <!-- Specifies the gravity within each cell. -->
         <attr name="gravity" />
     </declare-styleable>
     <declare-styleable name="ImageSwitcher">
@@ -3165,7 +3176,10 @@
         <attr name="visible" format="boolean" />
     </declare-styleable>
 
+    <!-- Drawable used to render several states. Each state is represented by
+         a child drawable. -->
     <declare-styleable name="StateListDrawable">
+        <!-- Indicates whether the drawable should be initially visible. -->
         <attr name="visible" />
         <!-- If true, allows the drawable's padding to change based on the
              current state that is selected.  If false, the padding will
@@ -3189,6 +3203,7 @@
         <attr name="exitFadeDuration" format="integer" />
     </declare-styleable>
 
+    <!-- Drawable used to render several animated frames. -->
     <declare-styleable name="AnimationDrawable">
         <attr name="visible" />
         <attr name="variablePadding" />
@@ -3198,6 +3213,7 @@
         <attr name="oneshot" format="boolean" />
     </declare-styleable>
 
+    <!-- Represents a single frame inside an AnimationDrawable. -->
     <declare-styleable name="AnimationDrawableItem">
         <!-- Amount of time (in milliseconds) to display this frame. -->
         <attr name="duration" format="integer" />
@@ -3206,12 +3222,21 @@
         <attr name="drawable" format="reference" />
     </declare-styleable>
 
+    <!-- Drawable used to render a geometric shape, with a gradient or a solid color. -->
     <declare-styleable name="GradientDrawable">
+        <!-- Indicates whether the drawable should intially be visible. -->
         <attr name="visible" />
+        <!-- Enables or disables dithering. -->
+        <attr name="dither" />
+        <!-- Indicates what shape to fill with a gradient. -->
         <attr name="shape">
+            <!-- Rectangle shape, with optional rounder corners. -->
             <enum name="rectangle" value="0" />
+            <!-- Oval shape. -->
             <enum name="oval" value="1" />
+            <!-- Line shape. -->
             <enum name="line" value="2" />
+            <!-- Ring shape. -->
             <enum name="ring" value="3" />
         </attr>
         <!-- Inner radius of the ring expressed as a ratio of the ring's width. For instance,
@@ -3226,71 +3251,123 @@
         <attr name="innerRadius" format="dimension" />
         <!-- Thickness of the ring. When defined, thicknessRatio is ignored. -->
         <attr name="thickness" format="dimension" />
+        <!-- Indicates whether the drawable's level affects the way the gradient is drawn. -->
         <attr name="useLevel" />
     </declare-styleable>
 
+    <!-- Used to specify the size of the shape for GradientDrawable. -->
     <declare-styleable name="GradientDrawableSize">
+        <!-- Width of the gradient shape. -->
         <attr name="width" />
+        <!-- Height of the gradient shape. -->
         <attr name="height" />
     </declare-styleable>
 
+    <!-- Used to describe the gradient used to fill the shape of a GradientDrawable. -->
     <declare-styleable name="GradientDrawableGradient">
+        <!-- Start color of the gradient. -->
         <attr name="startColor" format="color" />
-        <!-- Optional center color. For linear gradients, use centerX or centerY to place the center color. -->
+        <!-- Optional center color. For linear gradients, use centerX or centerY
+             to place the center color. -->
         <attr name="centerColor" format="color" />
+        <!-- End color of the gradient. -->
         <attr name="endColor" format="color" />
         <attr name="useLevel" format="boolean" />
+        <!-- Angle of the gradient. -->
         <attr name="angle" format="float" />
+        <!-- Type of gradient. The default type is linear. -->
         <attr name="type">
+            <!-- Linear gradient. -->
             <enum name="linear" value="0" />
+            <!-- Radial, or circular, gradient. -->
             <enum name="radial" value="1" />
+            <!-- Sweep, or angled or diamond, gradient. -->
             <enum name="sweep"  value="2" />
         </attr>
+        <!-- X coordinate of the origin of the gradient within the shape. -->
         <attr name="centerX" format="float|fraction" />
+        <!-- Y coordinate of the origin of the gradient within the shape. -->
         <attr name="centerY" format="float|fraction" />
+        <!-- Radius of the gradient, used only with radial gradient. -->
         <attr name="gradientRadius" format="float|fraction" />
     </declare-styleable>
 
+    <!-- Used to fill the shape of GradientDrawable with a solid color. -->
     <declare-styleable name="GradientDrawableSolid">
+        <!-- Solid color for the gradient shape. -->
         <attr name="color" format="color" />
     </declare-styleable>
 
+    <!-- Used to describe the optional stroke of a GradientDrawable. -->
     <declare-styleable name="GradientDrawableStroke">
+        <!-- Width of the gradient shape's stroke. -->
         <attr name="width" />
+        <!-- Color of the gradient shape's stroke. -->
         <attr name="color" />
+        <!-- Length of a dash in the stroke. -->
         <attr name="dashWidth" format="dimension" />
+        <!-- Gap between dashes in the stroke. -->
         <attr name="dashGap" format="dimension" />
     </declare-styleable>
 
+    <!-- Describes the corners for the rectangle shape of a GradientDrawable.
+         This can be used to render rounded corners. -->
     <declare-styleable name="DrawableCorners">
+        <!-- Defines the radius of the four corners. -->
         <attr name="radius" format="dimension" />
+        <!-- Radius of the top left corner. -->
         <attr name="topLeftRadius" format="dimension" />
+        <!-- Radius of the top right corner. -->
         <attr name="topRightRadius" format="dimension" />
+        <!-- Radius of the bottom left corner. -->
         <attr name="bottomLeftRadius" format="dimension" />
+        <!-- Radius of the bottom right corner. -->
         <attr name="bottomRightRadius" format="dimension" />
     </declare-styleable>
 
+    <!-- Used to specify the optional padding of a GradientDrawable. -->
     <declare-styleable name="GradientDrawablePadding">
+        <!-- Amount of left padding inside the gradient shape. -->
         <attr name="left" format="dimension" />
+        <!-- Amount of top padding inside the gradient shape. -->
         <attr name="top" format="dimension" />
+        <!-- Amount of right padding inside the gradient shape. -->
         <attr name="right" format="dimension" />
+        <!-- Amount of bottom padding inside the gradient shape. -->
         <attr name="bottom" format="dimension" />
     </declare-styleable>
 
+    <!-- Drawable used to render several drawables stacked on top of each other.
+         Each child drawable can be controlled individually. -->
     <declare-styleable name="LayerDrawable">
+        <!-- Indicates the opacity of the layer. This can be useful to allow the
+              system to enable drawing optimizations. The default value is
+              translucent. -->
         <attr name="opacity">
+            <!-- Indicates that the layer is opaque and contains no transparent
+                 nor translucent pixels. -->
             <enum name="opaque" value="-1" />
+            <!-- The layer is completely transparent (no pixel will be drawn.) -->
             <enum name="transparent" value="-2" />
+            <!-- The layer has translucent pixels. -->
             <enum name="translucent" value="-3" />
         </attr>
     </declare-styleable>
 
+    <!-- Describes an item (or child) of a LayerDrawable. -->
     <declare-styleable name="LayerDrawableItem">
+        <!-- Left coordinate of the layer. -->
         <attr name="left" />
+        <!-- Top coordinate of the layer. -->
         <attr name="top" />
+        <!-- Right coordinate of the layer. -->
         <attr name="right" />
+        <!-- Bottom coordinate of the layer. -->
         <attr name="bottom" />
+        <!-- Drawable used to render the layer. -->
         <attr name="drawable" />
+        <!-- Identifier of the layer. This can be used to retrieve the layer
+             from a drawbable container. -->
         <attr name="id" />
     </declare-styleable>
 
@@ -3306,6 +3383,7 @@
         <attr name="drawable" />
     </declare-styleable>
 
+    <!-- Drawable used to rotate another drawable. -->
     <declare-styleable name="RotateDrawable">
         <attr name="visible" />
         <attr name="fromDegrees" format="float" />
@@ -3464,6 +3542,8 @@
         <attr name="width" />
         <!-- Defines the height of the shape. -->
         <attr name="height" />
+        <!-- Enables or disables dithering. -->
+        <attr name="dither" />
     </declare-styleable>
 
     <!-- ========================== -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0edd33e..ce37943 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -194,6 +194,13 @@
     <!-- Boolean indicating whether the wifi chipset has dual frequency band support -->
     <bool translatable="false" name="config_wifi_dual_band_support">false</bool>
 
+    <!-- Boolean indicating whether the wifi chipset supports background scanning mechanism.
+         This mechanism allows the host to remain in suspend state and the dongle to actively
+         scan and wake the host when a configured SSID is detected by the dongle. This chipset
+         capability can provide power savings when wifi needs to be always kept on.
+         The driver commands needed to support the feature are BGSCAN-START and BGSCAN-STOP -->
+    <bool translatable="false" name="config_wifi_background_scan_support">false</bool>
+
     <!-- Flag indicating whether the keyguard should be bypassed when
          the slider is open.  This can be set or unset depending how easily
          the slider can be opened (for example, in a pocket or purse). -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4542575..c7f082b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1642,7 +1642,9 @@
   <!-- Default icon for applications that don't specify an icon. -->
   <public type="mipmap" name="sym_def_app_icon" id="0x010d0000" />
 
-  <!--  Theme attribute used to customize the text insertion cursor -->
-  <!--  Commented out for HC MR1 to prevent an API change -->
-  <!--  <public type="attr" name="textCursorDrawable" id="0x01010362" /> -->
+<!-- ===============================================================
+     Resources added in version 12 of the platform (Honeycomb / 3.1)
+     =============================================================== -->
+  <eat-comment />
+  <public type="attr" name="textCursorDrawable" id="0x01010362" />  
 </resources>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
index 1374e7f..41104fe 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
@@ -108,15 +108,6 @@
                 fail("thread in sleep is interrupted");
             }
             assertTrue("no uplink data connection after Wi-Fi tethering", mAct.pingTest(null));
-            // Wait for 5 minutes, and verify the data connection again.
-            // bug id: 3400027
-            try {
-                Thread.sleep(5 * 60 * 1000);
-            } catch (Exception e) {
-                fail("thread in sleep is interrupted");
-            }
-            // Verify the uplink data connection
-            assertTrue("no uplink data connection", mAct.pingTest(null));
             // Disable soft AP
             assertTrue(mAct.mWifiManager.setWifiApEnabled(config, false));
             // Wait for 30 seconds until Wi-Fi tethering is stopped
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
index 96b028a..672f252 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
@@ -250,8 +250,8 @@
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("connectInput iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.connectInput(adapter, device);
-            mTestUtils.disconnectInput(adapter, device);
+            mTestUtils.connectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE);
+            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE);
         }
 
         mTestUtils.unpair(adapter, device);
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
index effed76..85c5eaa 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
@@ -16,6 +16,8 @@
 
 package android.bluetooth;
 
+import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -238,6 +240,9 @@
                 case BluetoothProfile.HEADSET:
                     mConnectionAction = BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED;
                     break;
+                case BluetoothProfile.INPUT_DEVICE:
+                    mConnectionAction = BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED;
+                    break;
                 default:
                     mConnectionAction = null;
             }
@@ -270,47 +275,6 @@
         }
     }
 
-    private class ConnectInputReceiver extends FlagReceiver {
-        private static final int STATE_DISCONNECTED_FLAG = 1;
-        private static final int STATE_CONNECTING_FLAG = 1 << 1;
-        private static final int STATE_CONNECTED_FLAG = 1 << 2;
-        private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
-
-        private BluetoothDevice mDevice;
-
-        public ConnectInputReceiver(BluetoothDevice device, int expectedFlags) {
-            super(expectedFlags);
-
-            mDevice = device;
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
-                return;
-            }
-
-            if (BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED.equals(intent.getAction())) {
-                int state = intent.getIntExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, -1);
-                assertNotSame(-1, state);
-                switch (state) {
-                    case BluetoothInputDevice.STATE_DISCONNECTED:
-                        setFiredFlag(STATE_DISCONNECTED_FLAG);
-                        break;
-                    case BluetoothInputDevice.STATE_CONNECTING:
-                        setFiredFlag(STATE_CONNECTING_FLAG);
-                        break;
-                    case BluetoothInputDevice.STATE_CONNECTED:
-                        setFiredFlag(STATE_CONNECTED_FLAG);
-                        break;
-                    case BluetoothInputDevice.STATE_DISCONNECTING:
-                        setFiredFlag(STATE_DISCONNECTING_FLAG);
-                        break;
-                }
-            }
-        }
-    }
-
     private class ConnectPanReceiver extends FlagReceiver {
         private static final int STATE_DISCONNECTED_FLAG = 1;
         private static final int STATE_CONNECTING_FLAG = 1 << 1;
@@ -334,8 +298,8 @@
                 return;
             }
 
-            if (BluetoothPan.ACTION_PAN_STATE_CHANGED.equals(intent.getAction())) {
-                int state = intent.getIntExtra(BluetoothPan.EXTRA_PAN_STATE, -1);
+            if (BluetoothPan.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
+                int state = intent.getIntExtra(BluetoothPan.EXTRA_STATE, -1);
                 assertNotSame(-1, state);
                 switch (state) {
                     case BluetoothPan.STATE_DISCONNECTED:
@@ -366,6 +330,12 @@
                     case BluetoothProfile.HEADSET:
                         mHeadset = (BluetoothHeadset) proxy;
                         break;
+                    case BluetoothProfile.INPUT_DEVICE:
+                        mInput = (BluetoothInputDevice) proxy;
+                        break;
+                    case BluetoothProfile.PAN:
+                        mPan = (BluetoothPan) proxy;
+                        break;
                 }
             }
         }
@@ -379,6 +349,12 @@
                     case BluetoothProfile.HEADSET:
                         mHeadset = null;
                         break;
+                    case BluetoothProfile.INPUT_DEVICE:
+                        mInput = null;
+                        break;
+                    case BluetoothProfile.PAN:
+                        mPan = null;
+                        break;
                 }
             }
         }
@@ -393,6 +369,8 @@
     private Context mContext;
     private BluetoothA2dp mA2dp;
     private BluetoothHeadset mHeadset;
+    private BluetoothInputDevice mInput;
+    private BluetoothPan mPan;
 
     /**
      * Creates a utility instance for testing Bluetooth.
@@ -737,13 +715,13 @@
      * @param adapter The BT adapter.
      */
     public void enablePan(BluetoothAdapter adapter) {
-        BluetoothPan pan = new BluetoothPan(mContext);
-        assertNotNull(pan);
+        if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
+        assertNotNull(mPan);
 
         long start = System.currentTimeMillis();
-        pan.setBluetoothTethering(true);
+        mPan.setBluetoothTethering(true);
         long stop = System.currentTimeMillis();
-        assertTrue(pan.isTetheringOn());
+        assertTrue(mPan.isTetheringOn());
 
         writeOutput(String.format("enablePan() completed in %d ms", (stop - start)));
     }
@@ -755,13 +733,13 @@
      * @param adapter The BT adapter.
      */
     public void disablePan(BluetoothAdapter adapter) {
-        BluetoothPan pan = new BluetoothPan(mContext);
-        assertNotNull(pan);
+        if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
+        assertNotNull(mPan);
 
         long start = System.currentTimeMillis();
-        pan.setBluetoothTethering(false);
+        mPan.setBluetoothTethering(false);
         long stop = System.currentTimeMillis();
-        assertFalse(pan.isTetheringOn());
+        assertFalse(mPan.isTetheringOn());
 
         writeOutput(String.format("disablePan() completed in %d ms", (stop - start)));
     }
@@ -1078,142 +1056,6 @@
     }
 
     /**
-     * Connects the local device with a remote HID device and checks to make sure that the profile
-     * is connected and that the correct actions were broadcast.
-     *
-     * @param adapter The BT adapter.
-     * @param device The remote device.
-     */
-    public void connectInput(BluetoothAdapter adapter, BluetoothDevice device) {
-        int mask = (ConnectInputReceiver.STATE_CONNECTING_FLAG
-                | ConnectInputReceiver.STATE_CONNECTED_FLAG);
-        long start = -1;
-
-        if (!adapter.isEnabled()) {
-            fail(String.format("connectInput() bluetooth not enabled: device=%s", device));
-        }
-
-        if (!adapter.getBondedDevices().contains(device)) {
-            fail(String.format("connectInput() device not paired: device=%s", device));
-        }
-
-        BluetoothInputDevice inputDevice = new BluetoothInputDevice(mContext);
-        assertNotNull(inputDevice);
-        ConnectInputReceiver receiver = getConnectInputReceiver(device, mask);
-
-        int state = inputDevice.getInputDeviceState(device);
-        switch (state) {
-            case BluetoothInputDevice.STATE_CONNECTED:
-                removeReceiver(receiver);
-                return;
-            case BluetoothInputDevice.STATE_CONNECTING:
-                mask = 0; // Don't check for received intents since we might have missed them.
-                break;
-            case BluetoothInputDevice.STATE_DISCONNECTED:
-            case BluetoothInputDevice.STATE_DISCONNECTING:
-                start = System.currentTimeMillis();
-                assertTrue(inputDevice.connectInputDevice(device));
-                break;
-            default:
-                removeReceiver(receiver);
-                fail(String.format("connectInput() invalid state: device=%s, state=%d", device,
-                        state));
-        }
-
-        long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
-            state = inputDevice.getInputDeviceState(device);
-            if (state == BluetoothInputDevice.STATE_CONNECTED
-                    && (receiver.getFiredFlags() & mask) == mask) {
-                long finish = receiver.getCompletedTime();
-                if (start != -1 && finish != -1) {
-                    writeOutput(String.format("connectInput() completed in %d ms: device=%s",
-                            (finish - start), device));
-                } else {
-                    writeOutput(String.format("connectInput() completed: device=%s", device));
-                }
-                removeReceiver(receiver);
-                return;
-            }
-            sleep(POLL_TIME);
-        }
-
-        int firedFlags = receiver.getFiredFlags();
-        removeReceiver(receiver);
-        fail(String.format("connectInput() timeout: device=%s, state=%d (expected %d), "
-                + "flags=0x%x (expected 0x%s)", device, state, BluetoothInputDevice.STATE_CONNECTED,
-                firedFlags, mask));
-    }
-
-    /**
-     * Disconnects the local device with a remote HID device and checks to make sure that the
-     * profile is connected and that the correct actions were broadcast.
-     *
-     * @param adapter The BT adapter.
-     * @param device The remote device.
-     */
-    public void disconnectInput(BluetoothAdapter adapter, BluetoothDevice device) {
-        int mask = (ConnectInputReceiver.STATE_DISCONNECTING_FLAG
-                | ConnectInputReceiver.STATE_DISCONNECTED_FLAG);
-        long start = -1;
-
-        if (!adapter.isEnabled()) {
-            fail(String.format("disconnectInput() bluetooth not enabled: device=%s", device));
-        }
-
-        if (!adapter.getBondedDevices().contains(device)) {
-            fail(String.format("disconnectInput() device not paired: device=%s", device));
-        }
-
-        BluetoothInputDevice inputDevice = new BluetoothInputDevice(mContext);
-        assertNotNull(inputDevice);
-        ConnectInputReceiver receiver = getConnectInputReceiver(device, mask);
-
-        int state = inputDevice.getInputDeviceState(device);
-        switch (state) {
-            case BluetoothInputDevice.STATE_CONNECTED:
-            case BluetoothInputDevice.STATE_CONNECTING:
-                start = System.currentTimeMillis();
-                assertTrue(inputDevice.disconnectInputDevice(device));
-                break;
-            case BluetoothInputDevice.STATE_DISCONNECTED:
-                removeReceiver(receiver);
-                return;
-            case BluetoothInputDevice.STATE_DISCONNECTING:
-                mask = 0; // Don't check for received intents since we might have missed them.
-                break;
-            default:
-                removeReceiver(receiver);
-                fail(String.format("disconnectInput() invalid state: device=%s, state=%d", device,
-                        state));
-        }
-
-        long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
-            state = inputDevice.getInputDeviceState(device);
-            if (state == BluetoothInputDevice.STATE_DISCONNECTED
-                    && (receiver.getFiredFlags() & mask) == mask) {
-                long finish = receiver.getCompletedTime();
-                if (start != -1 && finish != -1) {
-                    writeOutput(String.format("disconnectInput() completed in %d ms: device=%s",
-                            (finish - start), device));
-                } else {
-                    writeOutput(String.format("disconnectInput() completed: device=%s", device));
-                }
-                removeReceiver(receiver);
-                return;
-            }
-            sleep(POLL_TIME);
-        }
-
-        int firedFlags = receiver.getFiredFlags();
-        removeReceiver(receiver);
-        fail(String.format("disconnectInput() timeout: device=%s, state=%d (expected %d), "
-                + "flags=0x%x (expected 0x%s)", device, state,
-                BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
-    }
-
-    /**
      * Connects the PANU to a remote NAP and checks to make sure that the PANU is connected and that
      * the correct actions were broadcast.
      *
@@ -1269,11 +1111,11 @@
             fail(String.format("%s device not paired: device=%s", methodName, device));
         }
 
-        BluetoothPan pan = new BluetoothPan(mContext);
-        assertNotNull(pan);
+        if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
+        assertNotNull(mPan);
         ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
 
-        int state = pan.getPanDeviceState(device);
+        int state = mPan.getConnectionState(device);
         switch (state) {
             case BluetoothPan.STATE_CONNECTED:
                 removeReceiver(receiver);
@@ -1286,7 +1128,7 @@
                 start = System.currentTimeMillis();
                 if (role == BluetoothPan.LOCAL_PANU_ROLE) {
                     Log.i("BT", "connect to pan");
-                    assertTrue(pan.connect(device));
+                    assertTrue(mPan.connect(device));
                 }
                 break;
             default:
@@ -1297,7 +1139,7 @@
 
         long s = System.currentTimeMillis();
         while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
-            state = pan.getPanDeviceState(device);
+            state = mPan.getConnectionState(device);
             if (state == BluetoothPan.STATE_CONNECTED
                     && (receiver.getFiredFlags() & mask) == mask) {
                 long finish = receiver.getCompletedTime();
@@ -1376,23 +1218,23 @@
             fail(String.format("%s device not paired: device=%s", methodName, device));
         }
 
-        BluetoothPan pan = new BluetoothPan(mContext);
-        assertNotNull(pan);
+        if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
+        assertNotNull(mPan);
         ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
 
-        int state = pan.getPanDeviceState(device);
+        int state = mPan.getConnectionState(device);
         switch (state) {
-            case BluetoothInputDevice.STATE_CONNECTED:
-            case BluetoothInputDevice.STATE_CONNECTING:
+            case BluetoothPan.STATE_CONNECTED:
+            case BluetoothPan.STATE_CONNECTING:
                 start = System.currentTimeMillis();
                 if (role == BluetoothPan.LOCAL_PANU_ROLE) {
-                    assertTrue(pan.disconnect(device));
+                    assertTrue(mPan.disconnect(device));
                 }
                 break;
-            case BluetoothInputDevice.STATE_DISCONNECTED:
+            case BluetoothPan.STATE_DISCONNECTED:
                 removeReceiver(receiver);
                 return;
-            case BluetoothInputDevice.STATE_DISCONNECTING:
+            case BluetoothPan.STATE_DISCONNECTING:
                 mask = 0; // Don't check for received intents since we might have missed them.
                 break;
             default:
@@ -1403,7 +1245,7 @@
 
         long s = System.currentTimeMillis();
         while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
-            state = pan.getPanDeviceState(device);
+            state = mPan.getConnectionState(device);
             if (state == BluetoothInputDevice.STATE_DISCONNECTED
                     && (receiver.getFiredFlags() & mask) == mask) {
                 long finish = receiver.getCompletedTime();
@@ -1478,24 +1320,17 @@
             int expectedFlags) {
         String[] actions = {
                 BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED,
-                BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED};
+                BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED,
+                BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED};
         ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile,
                 expectedFlags);
         addReceiver(receiver, actions);
         return receiver;
     }
 
-    private ConnectInputReceiver getConnectInputReceiver(BluetoothDevice device,
-            int expectedFlags) {
-        String[] actions = {BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED};
-        ConnectInputReceiver receiver = new ConnectInputReceiver(device, expectedFlags);
-        addReceiver(receiver, actions);
-        return receiver;
-    }
-
     private ConnectPanReceiver getConnectPanReceiver(BluetoothDevice device, int role,
             int expectedFlags) {
-        String[] actions = {BluetoothPan.ACTION_PAN_STATE_CHANGED};
+        String[] actions = {BluetoothPan.ACTION_CONNECTION_STATE_CHANGED};
         ConnectPanReceiver receiver = new ConnectPanReceiver(device, role, expectedFlags);
         addReceiver(receiver, actions);
         return receiver;
@@ -1511,15 +1346,25 @@
         long s = System.currentTimeMillis();
         switch (profile) {
             case BluetoothProfile.A2DP:
-                while (mA2dp != null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
+                while (mA2dp == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
                     sleep(POLL_TIME);
                 }
                 return mA2dp;
             case BluetoothProfile.HEADSET:
-                while (mHeadset != null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
+                while (mHeadset == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
                     sleep(POLL_TIME);
                 }
                 return mHeadset;
+            case BluetoothProfile.INPUT_DEVICE:
+                while (mInput == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
+                    sleep(POLL_TIME);
+                }
+                return mInput;
+            case BluetoothProfile.PAN:
+                while (mPan == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
+                    sleep(POLL_TIME);
+                }
+                return mPan;
             default:
                 return null;
         }
diff --git a/docs/html/guide/appendix/market-filters.jd b/docs/html/guide/appendix/market-filters.jd
index f826f43..ef1deba 100644
--- a/docs/html/guide/appendix/market-filters.jd
+++ b/docs/html/guide/appendix/market-filters.jd
@@ -24,6 +24,8 @@
 <li><a
 href="{@docRoot}guide/practices/compatibility.html">Android Compatibility</a></li>
 <li><code><a
+href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html">&lt;supports-gl-texture&gt;</a></code></li>
+<li><code><a
 href="{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens&gt;</a></code></li>
 <li><code><a
 href="{@docRoot}guide/topics/manifest/uses-configuration-element.html">&lt;uses-configuration&gt;</a></code></li>
@@ -395,5 +397,12 @@
 with alternative resources.</p>
     </td>
   </tr>
+  <tr>
+    <td><nobr><a href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html">{@code
+&lt;supports-gl-texture&gt;}</a></nobr></td>
+    <td>
+      <p>Android Market filters the application unless one or more of the GL texture compression formats supported by the application are also supported by the device. </p>
+    </td>
+  </tr>
 </table>
 
diff --git a/docs/html/guide/appendix/media-formats.jd b/docs/html/guide/appendix/media-formats.jd
index bac6bf4..8509466 100644
--- a/docs/html/guide/appendix/media-formats.jd
+++ b/docs/html/guide/appendix/media-formats.jd
@@ -168,7 +168,7 @@
 
 
 <tr>
-<td rowspan="3">Video</td>
+<td rowspan="4">Video</td>
 <td>H.263</td>
 <td style="text-align: center;"><big>&bull;</big></td>
 <td style="text-align: center;"><big>&bull;</big></td>
@@ -192,6 +192,14 @@
 <td>3GPP (.3gp)</td>
 </tr>
 
+<tr>
+<td>VP8</td>
+<td>&nbsp;</td>
+<td style="text-align: center;"><big>&bull;</big><br><small>(Android 2.3.3+)</small></td>
+<td>&nbsp;</td>
+<td><a href="http://www.webmproject.org/">WebM</a> (.webm)</td>
+</tr>
+
 </tbody></table>
 
 
diff --git a/docs/html/guide/developing/building/building-cmdline.jd b/docs/html/guide/developing/building/building-cmdline.jd
index 81c1178..5f193bc 100644
--- a/docs/html/guide/developing/building/building-cmdline.jd
+++ b/docs/html/guide/developing/building/building-cmdline.jd
@@ -72,7 +72,7 @@
       <p>This creates your debug <code>.apk</code> file inside the project <code>bin/</code> directory, named
       <code>&lt;your_project_name&gt;-debug.apk</code>. The file is already signed with
       the debug key and has been aligned with
-      <a href="{@docRoot}/guide/developing/tools/zipalign.html"><code>zipalign</code></a>.
+      <a href="{@docRoot}guide/developing/tools/zipalign.html"><code>zipalign</code></a>.
       </p>
     </li>
   </ol>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index d81b416..b13600c 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -60,7 +60,7 @@
       <li class="toggle-list">
         <div><a href="<?cs var:toroot ?>guide/topics/fundamentals/activities.html">
           <span class="en">Activities</span>
-        </a> <span class="new">new!</span></div>
+        </a> <span class="new-child">new!</span></div>
         <ul>
           <li><a href="<?cs var:toroot ?>guide/topics/fundamentals/fragments.html">
             <span class="en">Fragments</span>
@@ -69,18 +69,17 @@
             <span class="en">Loaders</span>
           </a> <span class="new">new!</span></li>
           <li><a href="<?cs var:toroot ?>guide/topics/fundamentals/tasks-and-back-stack.html">
-            <span class="en">Tasks and Back Stack</span>
-          </a> <span class="new">new!</span></li>
+            <span class="en">Tasks and Back Stack</span></a></li>
         </ul>
       </li>
       <li class="toggle-list">
         <div><a href="<?cs var:toroot ?>guide/topics/fundamentals/services.html">
           <span class="en">Services</span>
-        </a> <span class="new">new!</span></div>
+        </a></div>
         <ul>
           <li><a href="<?cs var:toroot ?>guide/topics/fundamentals/bound-services.html">
             <span class="en">Bound Services</span>
-          </a> <span class="new">new!</span></li>
+          </a></li>
         </ul>
       </li>
       <li><a href="<?cs var:toroot ?>guide/topics/providers/content-providers.html">
@@ -91,7 +90,7 @@
           </a></li>
       <li><a href="<?cs var:toroot ?>guide/topics/fundamentals/processes-and-threads.html">
             <span class="en">Processes and Threads</span>
-          </a> <span class="new">new!</span></li>
+          </a></li>
     </ul>
 
 
@@ -100,7 +99,7 @@
         <div><a href="<?cs var:toroot ?>guide/topics/ui/index.html">
             <span class="en">User Interface</span>
           </a>
-          <span class="new">more!</span></div>
+          <span class="new-child">new!</span></div>
         <ul>
           <li><a href="<?cs var:toroot ?>guide/topics/ui/declaring-layout.html">
                <span class="en">Declaring Layout</span>
@@ -130,10 +129,9 @@
               </a></li>
             </ul>
           </li>
-          <li>
-              <a href="<?cs var:toroot ?>guide/topics/ui/drag-drop.html">
-                  Dragging and Dropping
-              </a><span class="new">new!</span>
+          <li><a href="<?cs var:toroot ?>guide/topics/ui/drag-drop.html">
+                <span class="en">Dragging and Dropping</span>
+              </a> <span class="new">new!</span>
           </li>
           <li><a href="<?cs var:toroot ?>guide/topics/ui/themes.html">
                 <span class="en">Applying Styles and Themes</span>
@@ -225,6 +223,7 @@
           <li><a href="<?cs var:toroot ?>guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></li>
           <li><a href="<?cs var:toroot ?>guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></li>
           <li><a href="<?cs var:toroot ?>guide/topics/manifest/service-element.html">&lt;service&gt;</a></li>
+          <li><a href="<?cs var:toroot ?>guide/topics/manifest/supports-gl-texture-element.html">&lt;supports-gl-texture&gt;</a></li> 
           <li><a href="<?cs var:toroot ?>guide/topics/manifest/supports-screens-element.html">&lt;supports-screens&gt;</a></li>  <!-- ##api level 4## -->
           <li><a href="<?cs var:toroot ?>guide/topics/manifest/uses-configuration-element.html">&lt;uses-configuration&gt;</a></li>
           <li><a href="<?cs var:toroot ?>guide/topics/manifest/uses-feature-element.html">&lt;uses-feature&gt;</a></li> <!-- ##api level 4## -->
@@ -240,7 +239,7 @@
         <div><a href="<?cs var:toroot ?>guide/topics/graphics/index.html">
             <span class="en">Graphics</span>
           </a>
-          <span class="new">more!</span></div>
+          <span class="new-child">new!</span></div>
         <ul>
           <li><a href="<?cs var:toroot ?>guide/topics/graphics/2d-graphics.html">
                 <span class="en">2D Graphics</span>
@@ -250,10 +249,10 @@
               </a></li>
           <li><a href="<?cs var:toroot ?>guide/topics/graphics/renderscript.html">
                 <span class="en">3D with Renderscript</span>
-              </a><span class="new">new!</span></li>
+              </a> <span class="new">new!</span></li>
           <li><a href="<?cs var:toroot ?>guide/topics/graphics/animation.html">
                 <span class="en">Property Animation</span>
-              </a><span class="new">new!</span></li>
+              </a> <span class="new">new!</span></li>
           <li><a href="<?cs var:toroot ?>guide/topics/graphics/view-animation.html">
                 <span class="en">View Animation</span>
               </a></li>
@@ -653,6 +652,9 @@
       <li><a href="<?cs var:toroot ?>guide/practices/screens_support.html">
             <span class="en">Supporting Multiple Screens</span>
           </a></li>
+      <li><a href="<?cs var:toroot ?>guide/practices/optimizing-for-3.0.html">
+            <span class="en">Optimizing Apps for Android 3.0</span>
+          </a> <span class="new">new!</span></li>
       <li class="toggle-list">
         <div><a href="<?cs var:toroot ?>guide/practices/ui_guidelines/index.html">
                <span class="en">UI Guidelines</span>
diff --git a/docs/html/sdk/android-3.0-optimize.jd b/docs/html/guide/practices/optimizing-for-3.0.jd
similarity index 100%
rename from docs/html/sdk/android-3.0-optimize.jd
rename to docs/html/guide/practices/optimizing-for-3.0.jd
diff --git a/docs/html/guide/practices/ui_guidelines/activity_task_design.jd b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
index 7f35b04..31ad466 100644
--- a/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
@@ -1,4 +1,6 @@
 page.title=Activity and Task Design Guidelines
+parent.title=UI Guidelines
+parent.link=index.html
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/practices/ui_guidelines/menu_design.jd b/docs/html/guide/practices/ui_guidelines/menu_design.jd
index 840ee66..7751a7b 100644
--- a/docs/html/guide/practices/ui_guidelines/menu_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/menu_design.jd
@@ -1,4 +1,6 @@
 page.title=Menu Design Guidelines
+parent.title=UI Guidelines
+parent.link=index.html
 @jd:body
 	
 <div id="qv-wrapper">
diff --git a/docs/html/guide/practices/ui_guidelines/widget_design.jd b/docs/html/guide/practices/ui_guidelines/widget_design.jd
index e978069..49aa498 100644
--- a/docs/html/guide/practices/ui_guidelines/widget_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/widget_design.jd
@@ -1,4 +1,6 @@
 page.title=Widget Design Guidelines
+parent.title=UI Guidelines
+parent.link=index.html
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/graphics/renderscript.jd b/docs/html/guide/topics/graphics/renderscript.jd
index 0e64c78..60bffdb 100644
--- a/docs/html/guide/topics/graphics/renderscript.jd
+++ b/docs/html/guide/topics/graphics/renderscript.jd
@@ -115,7 +115,7 @@
     <code><em>ScriptC_renderscript_filename</em></code>.
     Accessor methods are generated, so the Android system layer can access the values.
     The <code>get</code> method comes with a one-way communication restriction. 
-    The Android system layer always caches the last value that is set and returns that during a call to a <code>get<code> method.
+    The Android system layer always caches the last value that is set and returns that during a call to a <code>get</code> method.
     If the native Renderscript code changes the value, the change does not propagate back to the Android system layer.
     If the global variables are initialized in the native Renderscript code, those values are used
     to initialize the corresponding values in the Android system. If global variables are marked as <code>const</code>,
@@ -373,11 +373,11 @@
         graphics context by calling 
         {@link android.renderscript.RenderScriptGL#bindProgramVertex bindProgramVertex()}. It is then used for all
         subsequent draw calls until you bind a new program. If the program has constant inputs, the
-        user needs to bind an allocation containing those inputs. The allocation’s type must match
+        user needs to bind an allocation containing those inputs. The allocation's type must match
         the one provided during creation. The Renderscript library then does all the necessary
         plumbing to send those constants to the graphics hardware. Varying inputs to the shader,
         such as position, normal, and texture coordinates are matched by name between the input
-        Element and the Mesh object being drawn. The signatures don’t have to be exact or in any
+        Element and the Mesh object being drawn. The signatures don't have to be exact or in any
         strict order. As long as the input name in the shader matches a channel name and size
         available on the mesh, the run-time would take care of connecting the two. Unlike OpenGL,
         there is no need to link the vertex and fragment programs.</p>
@@ -396,7 +396,7 @@
       <td>rs_program_fragment</td>
 
       <td><p>The Renderscript fragment program, also known as the fragment shader, is responsible for
-      manipulating pixel data in a user-defined way. It’s constructed from a GLSL shader string
+      manipulating pixel data in a user-defined way. It's constructed from a GLSL shader string
       containing the program body, textures inputs, and a Type object describing the constants used
       by the program. Like the vertex programs, when an allocation with constant input values is
       bound to the shader, its values are sent to the graphics program automatically. Note that the
@@ -445,7 +445,7 @@
       mip-maps are used and the amount of anisotropy required. There may be situations where
       hardware limitations prevent the exact behavior from being matched. In these cases, the
       runtime attempts to provide the closest possible approximation. For example, the user
-      requested 16x anisotropy, but only 8x was set because it’s the best available on the
+      requested 16x anisotropy, but only 8x was set because it's the best available on the
       hardware.</td>
     </tr>
 
diff --git a/docs/html/guide/topics/manifest/action-element.jd b/docs/html/guide/topics/manifest/action-element.jd
index d7ba78d..8ad94cd 100644
--- a/docs/html/guide/topics/manifest/action-element.jd
+++ b/docs/html/guide/topics/manifest/action-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;action&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/activity-alias-element.jd b/docs/html/guide/topics/manifest/activity-alias-element.jd
index 4521b4b..ba2c154 100644
--- a/docs/html/guide/topics/manifest/activity-alias-element.jd
+++ b/docs/html/guide/topics/manifest/activity-alias-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;activity-alias&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd
index 5e0b536..c910686 100644
--- a/docs/html/guide/topics/manifest/activity-element.jd
+++ b/docs/html/guide/topics/manifest/activity-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;activity&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
@@ -14,6 +16,7 @@
           android:<a href="#exclude">excludeFromRecents</a>=["true" | "false"]
           android:<a href="#exported">exported</a>=["true" | "false"]
           android:<a href="#finish">finishOnTaskLaunch</a>=["true" | "false"]
+          android:<a href="#hwaccel">hardwareAccelerated</a>=["true" | "false"]
           android:<a href="#icon">icon</a>="<i>drawable resource</i>"
           android:<a href="#label">label</a>="<i>string resource</i>"
           android:<a href="#lmode">launchMode</a>=["multiple" | "singleTop" |
@@ -286,6 +289,24 @@
 activity is ignored.  The activity is not re-parented, but destroyed.
 </p>
 
+<dt><a name="hwaccel"></a>{@code android:hardwareAccelerated}</dt>
+<dd>Whether or not hardware-accelerated rendering should be enabled for this
+Activity &mdash; "{@code true}" if it should be enabled, and "{@code false}" if
+not. The default value is "{@code false}".
+
+<p>Starting from Android 3.0, a hardware-accelerated OpenGL renderer is
+available to applications, to improve performance for many common 2D graphics
+operations. When the hardware-accelerated renderer is enabled, most operations
+in Canvas, Paint, Xfermode, ColorFilter, Shader, and Camera are accelerated.
+This results in smoother animations, smoother scrolling, and improved
+responsiveness overall, even for applications that do not explicitly make use
+the framework's OpenGL libraries. </p>
+
+<p>Note that not all of the OpenGL 2D operations are accelerated. If you enable
+the hardware-accelerated renderer, test your application to ensure that it can
+make use of the renderer without errors.</p>
+</dd>
+
 <dt><a name="icon"></a>{@code android:icon}</dt>
 <dd>An icon representing the activity. The icon is displayed to users when 
 a representation of the activity is required on-screen.  For example, icons 
diff --git a/docs/html/guide/topics/manifest/application-element.jd b/docs/html/guide/topics/manifest/application-element.jd
index 1fadc6e..41313ed 100644
--- a/docs/html/guide/topics/manifest/application-element.jd
+++ b/docs/html/guide/topics/manifest/application-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;application&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
@@ -9,6 +11,7 @@
              android:<a href="#desc">description</a>="<i>string resource</i>"
              android:<a href="#enabled">enabled</a>=["true" | "false"]
              android:<a href="#code">hasCode</a>=["true" | "false"]
+             android:<a href="#hwaccel">hardwareAccelerated</a>=["true" | "false"]
              android:<a href="#icon">icon</a>="<i>drawable resource</i>"
              android:<a href="#killrst">killAfterRestore</a>=["true" | "false"]
              android:<a href="#label">label</a>="<i>string resource</i>"
@@ -108,7 +111,26 @@
 <p>
 An application would not have any code of its own only if it's using nothing
 but built-in component classes, such as an activity that uses the {@link 
-android.app.AliasActivity} class, a rare occurrence.
+android.app.AliasActivity} class, a rare occurrence.</p>
+</dd>
+
+<dt><a name="hwaccel"></a>{@code android:hardwareAccelerated}</dt>
+<dd>Whether or not hardware-accelerated rendering should be enabled for all
+Activities and Views in this application &mdash; "{@code true}" if it
+should be enabled, and "{@code false}" if not. The default value is "{@code false}".
+
+<p>Starting from Android 3.0, a hardware-accelerated OpenGL renderer is
+available to applications, to improve performance for many common 2D graphics
+operations. When the hardware-accelerated renderer is enabled, most operations
+in Canvas, Paint, Xfermode, ColorFilter, Shader, and Camera are accelerated.
+This results in smoother animations, smoother scrolling, and improved
+responsiveness overall, even for applications that do not explicitly make use
+the framework's OpenGL libraries. </p>
+
+<p>Note that not all of the OpenGL 2D operations are accelerated. If you enable
+the hardware-accelerated renderer, test your application to ensure that it can
+make use of the renderer without errors.</p>
+</dd>
 
 <dt><a name="icon"></a>{@code android:icon}</dt>
 <dd>An icon for the application as whole, and the default icon for 
diff --git a/docs/html/guide/topics/manifest/category-element.jd b/docs/html/guide/topics/manifest/category-element.jd
index b9a1aa6..f392c0a 100644
--- a/docs/html/guide/topics/manifest/category-element.jd
+++ b/docs/html/guide/topics/manifest/category-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;category&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/compatible-screens-element.jd b/docs/html/guide/topics/manifest/compatible-screens-element.jd
index 9fb0fd2..8669874 100644
--- a/docs/html/guide/topics/manifest/compatible-screens-element.jd
+++ b/docs/html/guide/topics/manifest/compatible-screens-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;compatible-screens&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/data-element.jd b/docs/html/guide/topics/manifest/data-element.jd
index b77fd05..9b0d0df 100644
--- a/docs/html/guide/topics/manifest/data-element.jd
+++ b/docs/html/guide/topics/manifest/data-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;data&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/grant-uri-permission-element.jd b/docs/html/guide/topics/manifest/grant-uri-permission-element.jd
index 9dafe85..dc98cbb 100644
--- a/docs/html/guide/topics/manifest/grant-uri-permission-element.jd
+++ b/docs/html/guide/topics/manifest/grant-uri-permission-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;grant-uri-permission&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/instrumentation-element.jd b/docs/html/guide/topics/manifest/instrumentation-element.jd
index b18e777..9408b84 100644
--- a/docs/html/guide/topics/manifest/instrumentation-element.jd
+++ b/docs/html/guide/topics/manifest/instrumentation-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;instrumentation&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/intent-filter-element.jd b/docs/html/guide/topics/manifest/intent-filter-element.jd
index 2b1322c..d293400 100644
--- a/docs/html/guide/topics/manifest/intent-filter-element.jd
+++ b/docs/html/guide/topics/manifest/intent-filter-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;intent-filter&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/manifest-element.jd b/docs/html/guide/topics/manifest/manifest-element.jd
index 7f21e6b..a8125b3 100644
--- a/docs/html/guide/topics/manifest/manifest-element.jd
+++ b/docs/html/guide/topics/manifest/manifest-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;manifest&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/manifest-intro.jd b/docs/html/guide/topics/manifest/manifest-intro.jd
index d7a3e3e..0f20305 100644
--- a/docs/html/guide/topics/manifest/manifest-intro.jd
+++ b/docs/html/guide/topics/manifest/manifest-intro.jd
@@ -83,6 +83,8 @@
     <a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html">&lt;uses-configuration /&gt;</a>  <!-- ##api level 3## -->
     <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature /&gt;</a>  <!-- ##api level 4## -->
     <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens /&gt;</a>  <!-- ##api level 4## -->
+    <a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html">&lt;compatible-screens /&gt;</a>  <!-- ##api level 9## -->
+    <a href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html">&lt;supports-gl-texture /&gt;</a>  <!-- ##api level 11## -->
 
     <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a>
 
diff --git a/docs/html/guide/topics/manifest/meta-data-element.jd b/docs/html/guide/topics/manifest/meta-data-element.jd
index 101b05a..85a871d 100644
--- a/docs/html/guide/topics/manifest/meta-data-element.jd
+++ b/docs/html/guide/topics/manifest/meta-data-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;meta-data&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/path-permission-element.jd b/docs/html/guide/topics/manifest/path-permission-element.jd
index 5c271a7..e644d68 100644
--- a/docs/html/guide/topics/manifest/path-permission-element.jd
+++ b/docs/html/guide/topics/manifest/path-permission-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;path-permission&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/permission-element.jd b/docs/html/guide/topics/manifest/permission-element.jd
index ad64d5d..c256fb1 100644
--- a/docs/html/guide/topics/manifest/permission-element.jd
+++ b/docs/html/guide/topics/manifest/permission-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;permission&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/permission-group-element.jd b/docs/html/guide/topics/manifest/permission-group-element.jd
index 0ad76a6..fc1de1f 100644
--- a/docs/html/guide/topics/manifest/permission-group-element.jd
+++ b/docs/html/guide/topics/manifest/permission-group-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;permission-group&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/permission-tree-element.jd b/docs/html/guide/topics/manifest/permission-tree-element.jd
index 6d6cd0a..a9c00cd 100644
--- a/docs/html/guide/topics/manifest/permission-tree-element.jd
+++ b/docs/html/guide/topics/manifest/permission-tree-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;permission-tree&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/provider-element.jd b/docs/html/guide/topics/manifest/provider-element.jd
index c80b207..dd00224 100644
--- a/docs/html/guide/topics/manifest/provider-element.jd
+++ b/docs/html/guide/topics/manifest/provider-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;provider&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/receiver-element.jd b/docs/html/guide/topics/manifest/receiver-element.jd
index b208917..7012c0f 100644
--- a/docs/html/guide/topics/manifest/receiver-element.jd
+++ b/docs/html/guide/topics/manifest/receiver-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;receiver&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/service-element.jd b/docs/html/guide/topics/manifest/service-element.jd
index 0a44e2c..d9a81b3 100644
--- a/docs/html/guide/topics/manifest/service-element.jd
+++ b/docs/html/guide/topics/manifest/service-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;service&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/supports-gl-texture-element.jd b/docs/html/guide/topics/manifest/supports-gl-texture-element.jd
new file mode 100644
index 0000000..6c4a05a
--- /dev/null
+++ b/docs/html/guide/topics/manifest/supports-gl-texture-element.jd
@@ -0,0 +1,189 @@
+page.title=&lt;supports-gl-texture&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
+@jd:body
+
+<dl class="xml">
+
+<dt>syntax:</dt>
+<dd>
+<pre class="stx">
+&lt;supports-gl-texture android:<a href="#name">name</a>="<em>string</em>" /&gt;
+</pre>
+</dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code></dd>
+
+ <div class="sidebox-wrapper">
+  <img id="rule" src="{@docRoot}assets/images/grad-rule-qv.png">
+  <div id="qv-sub-rule">
+    <img src="{@docRoot}assets/images/icon_market.jpg"
+    style="float:left;margin:0;padding:0;">
+    <p style="color:#669999;">Android Market and <code
+    style="color:#669999;">&lt;supports-gl-texture&gt;</code> elements</p>
+    <p style="margin-top:1em;">Android Market filters applications according
+    to the texture compression formats that they support, to ensure that
+    they can be installed only on devices that can handle their textures
+    properly. Developers can use texture compression filtering
+    as a way of targeting specific device types, based on GPU platform.</p>
+    
+    <p style="margin-top:1em;" class="caution">For important information about how
+    Android Market uses <code>&lt;supports-gl-texture&gt;</code> elements as
+    the basis for filtering, please read <a href="#market-texture-filtering">Android
+    Market and texture compression filtering</a>, below.</p>
+</div> 
+</div>
+
+<dt>description:</dt>
+<dd>Declares a single GL texture compression format that is supported by
+the application.
+
+<p>An application "supports" a GL texture compression format if it is capable of
+providing texture assets that are compressed in that format, once the
+application is installed on a device. The application can provide the
+compressed assets locally, from inside the <code>.apk</code>, or it can download them
+from a server at runtime.</p>
+
+<p>Each <code>&lt;supports-gl-texture&gt;</code> element declares exactly one
+supported texture compression format, specified as the value of a
+<code>android:name</code> attribute. If your application supports multiple
+texture compression formats, you can declare multiple
+<code>&lt;supports-gl-texture&gt;</code> elements. For example:</p>
+
+<pre>&lt;supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" /&gt;
+&lt;supports-gl-texture android:name="GL_OES_compressed_paletted_texture" /&gt;</pre>
+
+<p>Declared <code>&lt;supports-gl-texture&gt;</code> elements are informational,
+meaning that the Android system itself does not examine the elements at install
+time to ensure matching support on the device. However, other services
+(such as Android Market) or applications can check your application's
+<code>&lt;supports-gl-texture&gt;</code> declarations as part of handling or
+interacting with your application. For this reason, it's very important that
+you declare all of the texture compression formats (from the list below) that
+your application is capable of supporting. </p>
+
+<p>Applications and devices typically declare their supported GL texture
+compression formats using the same set of well-known strings, as listed below.
+The set of format strings may grow over time, as needed, and since the values
+are strings, applications are free to declare other formats as needed.</p>
+
+<p>Assuming that the application is built with SDK Platform Tools r3 or higher,
+filtering based on the <code>&lt;supports-gl-texture></code> element is activated
+for all API levels.</p>
+
+<dt>attributes:</dt>
+
+<dd>
+<dl class="attr">
+
+  <dt><a name="name"></a>{@code android:name}</dt>
+  <dd>Specifies a single GL texture compression format supported by the application,
+  as a descriptor string. Common descriptor values are listed in the table below.
+
+<table>
+<tr>
+<th>Texture Compression Format Descriptor</th>
+<th>Comments</th>
+</tr>
+<tr>
+<td><code>GL_OES_compressed_ETC1_RGB8_texture</code></td>
+<td>Ericsson texture compression. Specified in OpenGL ES 2.0 and available in all
+Android-powered devices that support OpenGL ES 2.0.</td>
+</tr>
+<tr>
+<td><code>GL_OES_compressed_paletted_texture</code></td>
+<td>Generic paletted texture compression.</td>
+</tr>
+<tr>
+<td><code>GL_AMD_compressed_3DC_texture</code></td>
+<td>ATI 3Dc texture compression. </td>
+</tr>
+<tr>
+<td><code>GL_AMD_compressed_ATC_texture</code></td>
+<td>ATI texture compression. Available on devices running Adreno GPU, including
+HTC Nexus One, Droid Incredible, EVO, and others. For widest compatibility,
+devices may also declare a <code>&lt;supports-gl-texture&gt;</code> element with the
+descriptor <code>GL_ATI_texture_compression_atitc</code>. </td>
+</tr>
+<tr>
+<td><code>GL_EXT_texture_compression_latc</code></td>
+<td>Luminance alpha texture compression. </td>
+</tr>
+<tr>
+<td><code>GL_EXT_texture_compression_dxt1</code></td>
+<td>S3 DXT1 texture compression. Supported on devices running Nvidia Tegra2
+platform, including Motorala Xoom, Motorola Atrix, Droid Bionic, and
+others.</td>
+</tr>
+<tr>
+<td><code>GL_EXT_texture_compression_s3tc</code></td>
+<td>S3 texture compression, nonspecific to DXT variant. Supported on devices
+running Nvidia Tegra2 platform, including Motorala Xoom, Motorola Atrix, Droid
+Bionic, and others. If your application requires a specific DXT variant, declare
+that descriptor instead of this one.</td>
+</tr>
+<tr>
+<td><code>GL_IMG_texture_compression_pvrtc</code></td>
+<td>PowerVR texture compression. Available in devices running PowerVR SGX530/540
+GPU, such as Motorola DROID series; Samsung Galaxy S, Nexus S, and Galaxy Tab;
+and others.</td>
+</tr>
+</table>
+
+</dd>
+</dl></dd>
+
+<!-- ##api level indication##
+<dt>introduced in:</dt>
+<dd>API Level </dd>-->
+
+<dt>see also:</dt>
+<dd>
+  <ul>
+    <li><a href="{@docRoot}guide/appendix/market-filters.html">Android Market Filters</a></li>
+  </ul>
+</dd>
+
+<h2 id="market-texture-filtering">Android Market and texture compression filtering</h2>
+
+<p>Android Market filters the applications that are visible to users, so that
+users can see and download only those applications that are compatible with
+their devices. One of the ways Market filters applications is by texture
+compression compatibility, giving you control over the availability of your
+application to various devices, based on the capabilities of their GPUs.</p>
+
+<p>To determine an application's texture compression compatibility with a given
+user's device, Android Market compares:</p>
+
+<ul>
+<li>Texture compression formats that are supported by the application &mdash;
+an application declares its supported texture compression formats in
+<code>&lt;supports-gl-texture&gt;</code> elements in its manifest <br/>with...</li>
+<li>Texture compression formats that are supported by the GPU on the device &mdash;
+a device reports the formats it supports as read-only system properties.</li>
+</ul>
+
+<p>Each time you upload an application to the Android Market Publisher Site,
+Android Market scans the application's manifest file and looks for any
+<code>&lt;supports-gl-texture&gt;</code> elements. It extracts the
+format descriptors from the elements and stores them internally as
+metadata associated with the application <code>.apk</code> and the application
+version. </p>
+
+<p>When a user searches or browses for applications on Android Market,
+the service compares the texture compression formats supported by the application
+with those supported by the user's device. The comparison is based on the format
+descriptor strings and a match must be exact.</p>
+
+<p>If <em>any</em> of an application's supported texture compression formats is
+also supported by the device, Android Market allows the user to see the
+application and potentially download it. Otherwise, if none of the application's
+formats is supported by the device, Android Market filters the application so
+that it is not available for download. </p>
+
+<p>If an application does not declare any <code>&lt;supports-gl-texture&gt;</code> elements,
+Android Market does not apply any filtering based on GL texture compression format.</p>
+
+</dl>
+
diff --git a/docs/html/guide/topics/manifest/supports-screens-element.jd b/docs/html/guide/topics/manifest/supports-screens-element.jd
index 92c769e..ee99a37 100644
--- a/docs/html/guide/topics/manifest/supports-screens-element.jd
+++ b/docs/html/guide/topics/manifest/supports-screens-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;supports-screens&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/uses-configuration-element.jd b/docs/html/guide/topics/manifest/uses-configuration-element.jd
index 4578c63..20ec85f 100755
--- a/docs/html/guide/topics/manifest/uses-configuration-element.jd
+++ b/docs/html/guide/topics/manifest/uses-configuration-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;uses-configuration&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <!-- ##api level 3##  see comment below -->
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
index 0828e8b..fec6a98 100644
--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;uses-feature&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/uses-library-element.jd b/docs/html/guide/topics/manifest/uses-library-element.jd
index 1d38c1a..d94ad9f 100644
--- a/docs/html/guide/topics/manifest/uses-library-element.jd
+++ b/docs/html/guide/topics/manifest/uses-library-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;uses-library&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
@@ -44,7 +46,7 @@
         <dd>
             Android Market filters applications based on the libraries installed on the
             user's device. For more information about filtering, see the topic
-            <a href="{@docRoot}/guide/appendix/market-filters.html">Market Filters</a>.
+            <a href="{@docRoot}guide/appendix/market-filters.html">Market Filters</a>.
         </dd>
     </dl>
     <p>
diff --git a/docs/html/guide/topics/manifest/uses-permission-element.jd b/docs/html/guide/topics/manifest/uses-permission-element.jd
index 085b9f0..967fc5a 100644
--- a/docs/html/guide/topics/manifest/uses-permission-element.jd
+++ b/docs/html/guide/topics/manifest/uses-permission-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;uses-permission&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd
index 971d4cb..b371f34 100644
--- a/docs/html/guide/topics/manifest/uses-sdk-element.jd
+++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd
@@ -1,4 +1,6 @@
 page.title=&lt;uses-sdk&gt;
+parent.title=The AndroidManifest.xml File
+parent.link=manifest-intro.html
 @jd:body
 
 <dl class="xml">
diff --git a/docs/html/guide/topics/ui/drag-drop.jd b/docs/html/guide/topics/ui/drag-drop.jd
index c33c507..0329c192 100644
--- a/docs/html/guide/topics/ui/drag-drop.jd
+++ b/docs/html/guide/topics/ui/drag-drop.jd
@@ -1,5 +1,8 @@
 page.title=Dragging and Dropping
+parent.title=User Interface
+parent.link=index.html
 @jd:body
+
 <div id="qv-wrapper">
     <div id="qv">
         <h2>Quickview</h2>
diff --git a/docs/html/guide/topics/ui/notifiers/index.jd b/docs/html/guide/topics/ui/notifiers/index.jd
index d29324c..8fc57fc 100644
--- a/docs/html/guide/topics/ui/notifiers/index.jd
+++ b/docs/html/guide/topics/ui/notifiers/index.jd
@@ -1,4 +1,6 @@
 page.title=Notifying the User
+parent.title=User Interface
+parent.link=../index.html
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/resources/community-more.jd b/docs/html/resources/community-more.jd
index 9f16fea..df72926 100644
--- a/docs/html/resources/community-more.jd
+++ b/docs/html/resources/community-more.jd
@@ -24,7 +24,11 @@
 </tr>
 </table>
 
-<p>If you haven't used IRC before, check <a href="http://en.wikipedia.org/wiki/List_of_IRC_clients">http://en.wikipedia.org/wiki/List_of_IRC_clients &raquo;</a> for a helpful list of IRC clients. Alternatively, you could also use this <a href="http://java.freenode.net/index.php?channel=android-dev">web interface &raquo;</a>, which does not require any installation, to join discussions on the Android IRC channels.  </p>
+<p>If you haven't used IRC before, check <a
+href="http://en.wikipedia.org/wiki/List_of_IRC_clients">http://en.wikipedia.org/wiki/
+List_of_IRC_clients &raquo;</a> for a helpful list of IRC clients. Alternatively, you could also use
+this <a href="http://webchat.freenode.net/?channels=android-dev">web interface &raquo;</a>, which
+does not require any installation, to join discussions on the Android IRC channels.  </p>
 
 <p>Here are some tips for using IRC:</h4>
 
diff --git a/docs/html/resources/resources-data.js b/docs/html/resources/resources-data.js
index b80e59a..e919de9 100644
--- a/docs/html/resources/resources-data.js
+++ b/docs/html/resources/resources-data.js
@@ -496,7 +496,7 @@
     }
   },
   {
-    tags: ['sample', 'new'],
+    tags: ['sample', 'new', 'newfeature', 'performance', 'gamedev', 'gl'],
     path: 'samples/Renderscript/index.html',
     title: {
       en: 'Renderscript'
diff --git a/docs/html/sdk/android-3.0-highlights.jd b/docs/html/sdk/android-3.0-highlights.jd
index 591f088..ebeb3789 100644
--- a/docs/html/sdk/android-3.0-highlights.jd
+++ b/docs/html/sdk/android-3.0-highlights.jd
@@ -46,7 +46,9 @@
 <p>Welcome to Android 3.0!</p>
 
 <p>The Android 3.0 platform introduces many new and exciting features for users and developers. 
-This document provides a glimpse of some of the new features and technologies, as delivered in the Android 3.0 Preview SDK. For more information about the SDK or how to download it, please see the <a href="{@docRoot}sdk/preview/index.html">Preview SDK</a> document.</p>
+This document provides a glimpse of some of the new features and technologies, as delivered in
+Android 3.0. For a more detailed look at new developer APIs, see the <a
+href="{@docRoot}sdk/android-3.0.html">Android 3.0 Platform</a> document.</p>
 
 <ul>
   <li><a href="#UserFeatures">New User Features</a></li>
@@ -259,7 +261,8 @@
 </object>
 </div>
 
-<p>For more information about the new developer APIs, see the Android 3.0 Platform notes in the SDK Preview documentation, available by download through the Android SDK Manager.</p>
+<p>For more information about the new developer APIs, see the <a
+href="{@docRoot}sdk/android-3.0.html">Android 3.0 Platform</a> document.</p>
 
 <p>For a video overview of platform features, see the Android 3.0 Sneak Peek. </p>
 
diff --git a/docs/html/sdk/android-3.0.jd b/docs/html/sdk/android-3.0.jd
index 6c88146..6c087bb 100644
--- a/docs/html/sdk/android-3.0.jd
+++ b/docs/html/sdk/android-3.0.jd
@@ -1,4 +1,4 @@
-page.title=Android 3.0 Platform Preview
+page.title=Android 3.0 Platform
 sdk.platform.version=3.0
 sdk.platform.apiLevel=11
 @jd:body
@@ -25,7 +25,7 @@
 
 <h2>See Also</h2>
 <ol>
-  <li><a href="{@docRoot}sdk/android-3.0-optimize.html">Optimizing Apps for Android 3.0</a></li>
+  <li><a href="{@docRoot}guide/practices/optimizing-for-3.0.html">Optimizing Apps for Android 3.0</a></li>
 </ol>
 
 </div>
@@ -48,10 +48,12 @@
 href="{@docRoot}sdk/android-{@sdkPlatformVersion}-highlights.html">Platform
 Highlights</a>.</p>
 
-<p>Also see the <a href="{@docRoot}sdk/android-3.0-optimize.html">Optimizing Apps for Android
-3.0</a> document for information about how to optimize your existing applications for Android 3.0
-devices, even if you want to remain compatible with previous versions.</p>
-
+<p class="note"><strong>Note:</strong>
+If you've already published an Android application, please test and optimize your application on
+Android 3.0 as soon as possible. You should do so to be sure your application provides the best
+experience possible on the latest Android-powered devices. For information about what you can do,
+read <a href="{@docRoot}guide/practices/optimizing-for-3.0.html">Optimizing Apps for Android
+3.0</a>.</p>
 
 
 <h2 id="relnotes">Revisions</h2>
@@ -866,8 +868,8 @@
 <h3>JSON utilities</h3>
 
 <p>New classes, {@link android.util.JsonReader} and {@link android.util.JsonWriter}, help you
-read and write JSON streams. The new APIs compliment the {@link org.json} classes which manipulate a
-document in memory.</p>
+read and write JSON streams. The new APIs complement the {@link org.json} classes, which manipulate
+a document in memory.</p>
 
 <p>You can create an instance of {@link android.util.JsonReader} by calling
 its constructor method and passing the {@link java.io.InputStreamReader} that feeds the JSON string.
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index df8869e..7f6f0105 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -2,20 +2,20 @@
 sdk.redirect=0
 
 sdk.win_installer=installer_r10-windows.exe
-sdk.win_installer_bytes=32845713
-sdk.win_installer_checksum=4e4356c472a6271ac9c062df0219dcb3
+sdk.win_installer_bytes=32878481
+sdk.win_installer_checksum=8ffa2dd734829d0bbd3ea601b50b36c7
 
 sdk.win_download=android-sdk_r10-windows.zip
-sdk.win_bytes=30112516
-sdk.win_checksum=643a75d99f5d4ca39dcf743fe894d599
+sdk.win_bytes=32832260
+sdk.win_checksum=1e42b8f528d9ca6d9b887c58c6f1b9a2
 
 sdk.mac_download=android-sdk_r10-mac_x86.zip
-sdk.mac_bytes=28224540
-sdk.mac_checksum=4d0a99a458e4f4bde65a01f8545f27e9
+sdk.mac_bytes=28847132
+sdk.mac_checksum=e3aa5578a6553b69cc36659c9505be3f
 
 sdk.linux_download=android-sdk_r10-linux_x86.tgz
-sdk.linux_bytes=26556013
-sdk.linux_checksum=10cafdd44771bfe2ba9d4440886389e7
+sdk.linux_bytes=26981997
+sdk.linux_checksum=c022dda3a56c8a67698e6a39b0b1a4e0
 
 @jd:body
 
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index 40231a3..bc9ba4b 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -1,16 +1,16 @@
 ndk=true
 
-ndk.win_download=android-ndk-r6-windows.zip
-ndk.win_bytes=64147764
-ndk.win_checksum=771b56328b7fc7751aa8040fb9dd09f0
+ndk.win_download=android-ndk-r5b-windows.zip
+ndk.win_bytes=61299831
+ndk.win_checksum=87745ada305ab639399161ab4faf684c
 
-ndk.mac_download=android-ndk-r6-darwin-x86.tar.bz2
-ndk.mac_bytes=50244722
-ndk.mac_checksum=d107f6d63478b73e09ed2eecd4c62bd3
+ndk.mac_download=android-ndk-r5b-darwin-x86.tar.bz2
+ndk.mac_bytes=50210863
+ndk.mac_checksum=019a14622a377b3727ec789af6707037
 
-ndk.linux_download=android-ndk-r6-linux-x86.tar.bz2
-ndk.linux_bytes=44088689
-ndk.linux_checksum=c83c3ab5a5e5a3b3fe7b907735ce77d4
+ndk.linux_download=android-ndk-r5b-linux-x86.tar.bz2
+ndk.linux_bytes=44138539
+ndk.linux_checksum=4c0045ddc2bfd657be9d5177d0e0b7e7
 
 page.title=Android NDK
 @jd:body
@@ -61,55 +61,6 @@
 
 <div class="toggleable open">
     <a href="#"
-         onclick="return toggleDiv(this)"><img src="{@docRoot}assets/images/triangle-opened.png"
-         class="toggle-img"
-         height="9px"
-         width="9px" /> Android NDK, Revision 6</a> <em>(February 2011)</em>
-
-    <div class="toggleme">
-      <p>This release of the NDK introduces the following header files:</p>
-        <ul>
-          <li><p><code>&lt;android/asset_manager.h&gt;</code>: Allows access to assets
-          using 64-bit file offsets and sizes. This is useful for very large assets that exceed
-          2GB, as required by some games. The following APIs are provided:<p>
-              <ul>
-                <li><code>AAsset_getLength64</code></li>
-                <li><code>AAsset_getRemainingLength64</code></li>
-                <li><code>AAsset_openFileDescriptor64</code></li>
-                <li><code>AAsset_seek64</code></li>
-              </ul>
-          </li>
-          
-          <li><code>&lt;android/input.h&gt;</code>: Provides the following AMETA_XXX constants 
-          that are related to the new input framework in Honeycomb:
-<pre>              
-AMETA_FUNCTION_ON = 0x08,
-AMETA_CTRL_ON = 0x1000,
-AMETA_CTRL_LEFT_ON = 0x2000,
-AMETA_CTRL_RIGHT_ON = 0x4000,
-AMETA_META_ON = 0x10000,
-AMETA_META_LEFT_ON = 0x20000,
-AMETA_META_RIGHT_ON = 0x40000,
-AMETA_CAPS_LOCK_ON = 0x100000,
-AMETA_NUM_LOCK_ON = 0x200000,
-AMETA_SCROLL_LOCK_ON = 0x400000,
-</pre>
-          </li>
-          
-          <li><code>&lt;android/keycodes&gt;</code>: Provides <code>AKEYCODE_XXX</code>
-          constants that are related to the new input framework in Honeycomb.
-          </li>
-          
-          <li><code>&lt;android/native_activity.h&gt;</code>: Adds a new field to the
-          system-allocated <code>ANativeActivity</code> structure named <code>obbPath</code> that
-          contains the path of your application's OBB files, if any.
-          </li>
-  </ul>
-  </div>
-  </div>
-
-<div class="toggleable closed">
-    <a href="#"
          onclick="return toggleDiv(this)"><img src="{@docRoot}assets/images/triangle-closed.png"
          class="toggle-img"
          height="9px"
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index c1894d8..a1c26db 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -80,7 +80,6 @@
         <div><a href="<?cs var:toroot ?>sdk/android-3.0.html">
         <span class="en">Android 3.0 Platform</span></a> <span class="new">new!</span></div>
         <ul>
-          <li><a href="<?cs var:toroot ?>sdk/android-3.0-optimize.html">Optimizing Apps for 3.0</a></li> 
           <li><a href="<?cs var:toroot ?>sdk/android-3.0-highlights.html">Platform Highlights</a></li> 
           <li><a href="<?cs var:toroot ?>sdk/api_diff/11/changes.html">API Differences Report &raquo;</a></li>
         </ul>
@@ -152,8 +151,8 @@
       <span style="display:none" class="zh-TW"></span>
     </h2>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r6</a>
-        <span class="new">new!</span></li>
+      <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r5b</a>
+        </li>
       <li><a href="<?cs var:toroot ?>sdk/ndk/overview.html">What is the NDK?</a></li>
     </ul>
   </li>
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index cffee5f..8d17561 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -240,7 +240,7 @@
         /**
          * The resulting height of the bitmap, set independent of the state of
          * inJustDecodeBounds. However, if there is an error trying to decode,
-         * outHeight will be set to -1.
+         * outHeight will be set to -1. 
          */
         public int outHeight;
 
diff --git a/graphics/java/android/graphics/Camera.java b/graphics/java/android/graphics/Camera.java
index 530655f..7ef35a9 100644
--- a/graphics/java/android/graphics/Camera.java
+++ b/graphics/java/android/graphics/Camera.java
@@ -16,24 +16,115 @@
 
 package android.graphics;
 
-
+/**
+ * A camera instance can be used to compute 3D transformations and
+ * generate a matrix that can be applied, for instance, on a
+ * {@link Canvas}.
+ */
 public class Camera {
-
+    /**
+     * Creates a new camera, with empty transformations.
+     */
     public Camera() {
         nativeConstructor();
     }
 
+    /**
+     * Saves the camera state. Each save should be balanced
+     * with a call to {@link #restore()}.
+     * 
+     * @see #save() 
+     */
     public native void save();
+
+    /**
+     * Restores the saved state, if any.
+     * 
+     * @see #restore() 
+     */
     public native void restore();
 
+    /**
+     * Applies a translation transform on all three axis.
+     * 
+     * @param x The distance to translate by on the X axis
+     * @param y The distance to translate by on the Y axis
+     * @param z The distance to translate by on the Z axis
+     */
     public native void translate(float x, float y, float z);
+
+    /**
+     * Applies a rotation transform around the X axis.
+     * 
+     * @param deg The angle of rotation around the X axis, in degrees
+     * 
+     * @see #rotateY(float)
+     * @see #rotateZ(float)
+     * @see #rotate(float, float, float)
+     */
     public native void rotateX(float deg);
+
+    /**
+     * Applies a rotation transform around the Y axis.
+     * 
+     * @param deg The angle of rotation around the Y axis, in degrees
+     * 
+     * @see #rotateX(float)
+     * @see #rotateZ(float)
+     * @see #rotate(float, float, float) 
+     */
     public native void rotateY(float deg);
+
+    /**
+     * Applies a rotation transform around the Z axis.
+     * 
+     * @param deg The angle of rotation around the Z axis, in degrees
+     * 
+     * @see #rotateX(float)
+     * @see #rotateY(float)
+     * @see #rotate(float, float, float)
+     */    
     public native void rotateZ(float deg);
 
+    /**
+     * Applies a rotation transform around all three axis.
+     * 
+     * @param x The angle of rotation around the X axis, in degrees
+     * @param y The angle of rotation around the Y axis, in degrees
+     * @param z The angle of rotation around the Z axis, in degrees
+     * 
+     * @see #rotateX(float)
+     * @see #rotateY(float)
+     * @see #rotateZ(float)
+     */
+    public native void rotate(float x, float y, float z);
+
+    /**
+     * Sets the location of the camera. The default location is set at
+     * 0, 0, -8.
+     * 
+     * @param x The x location of the camera
+     * @param y The y location of the camera
+     * @param z The z location of the camera
+     */
+    public native void setLocation(float x, float y, float z);
+
+    /**
+     * Computes the matrix corresponding to the current transformation
+     * and copies it to the supplied matrix object.
+     * 
+     * @param matrix The matrix to copy the current transforms into
+     */
     public void getMatrix(Matrix matrix) {
         nativeGetMatrix(matrix.native_instance);
     }
+
+    /**
+     * Computes the matrix corresponding to the current transformation
+     * and applies it to the specified Canvas.
+     * 
+     * @param canvas The Canvas to set the transform matrix onto
+     */
     public void applyToCanvas(Canvas canvas) {
         nativeApplyToCanvas(canvas.mNativeCanvas);
     }
@@ -41,7 +132,11 @@
     public native float dotWithNormal(float dx, float dy, float dz);
     
     protected void finalize() throws Throwable {
-        nativeDestructor();
+        try {
+            nativeDestructor();
+        } finally {
+            super.finalize();
+        }
     }
 
     private native void nativeConstructor();
@@ -51,4 +146,3 @@
     
     int native_instance;
 }
-
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 136e9b4..965abe9 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -74,6 +74,8 @@
      */
     public static final int DIRECTION_RTL = 1;
     
+    // This field is used to finalize the native Canvas properly
+    @SuppressWarnings({"UnusedDeclaration"})
     private final CanvasFinalizer mFinalizer;
 
     private static class CanvasFinalizer {
@@ -480,6 +482,7 @@
      * 
      * @hide
      */
+    @SuppressWarnings({"UnusedDeclaration"})
     public int getNativeMatrix() {
         return 0;
     }
@@ -945,10 +948,19 @@
     }
 
     /**
-     * Draw the specified arc, which will be scaled to fit inside the
-     * specified oval. If the sweep angle is >= 360, then the oval is drawn
+     * <p>Draw the specified arc, which will be scaled to fit inside the
+     * specified oval.</p>
+     * 
+     * <p>If the start angle is negative or >= 360, the start angle is treated
+     * as start angle modulo 360.</p>
+     * 
+     * <p>If the sweep angle is >= 360, then the oval is drawn
      * completely. Note that this differs slightly from SkPath::arcTo, which
-     * treats the sweep angle mod 360.
+     * treats the sweep angle modulo 360. If the sweep angle is negative,
+     * the sweep angle is treated as sweep angle modulo 360</p>
+     * 
+     * <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the
+     * geometric angle of 0 degrees (3 o'clock on a watch.)</p>
      *
      * @param oval       The bounds of oval used to define the shape and size
      *                   of the arc
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 65c6ccf..33f050c 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -624,6 +624,8 @@
         
         int shapeType = a.getInt(
                 com.android.internal.R.styleable.GradientDrawable_shape, RECTANGLE);
+        boolean dither = a.getBoolean(
+                com.android.internal.R.styleable.GradientDrawable_dither, false);
         
         if (shapeType == RING) {
             st.mInnerRadius = a.getDimensionPixelSize(
@@ -645,10 +647,11 @@
         a.recycle();
         
         setShape(shapeType);
-        
+        setDither(dither);
+
         int type;
 
-        final int innerDepth = parser.getDepth()+1;
+        final int innerDepth = parser.getDepth() + 1;
         int depth;
         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                && ((depth=parser.getDepth()) >= innerDepth
@@ -811,11 +814,12 @@
                         com.android.internal.R.styleable.DrawableCorners_bottomRightRadius, radius);
                 if (topLeftRadius != radius || topRightRadius != radius ||
                         bottomLeftRadius != radius || bottomRightRadius != radius) {
+                    // The corner radii are specified in clockwise order (see Path.addRoundRect())
                     setCornerRadii(new float[] {
                             topLeftRadius, topLeftRadius,
                             topRightRadius, topRightRadius,
-                            bottomLeftRadius, bottomLeftRadius,
-                            bottomRightRadius, bottomRightRadius
+                            bottomRightRadius, bottomRightRadius,
+                            bottomLeftRadius, bottomLeftRadius
                     });
                 }
                 a.recycle();
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index cb8774d..4445b6a 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -286,7 +286,7 @@
     protected boolean inflateTag(String name, Resources r, XmlPullParser parser,
             AttributeSet attrs) {
 
-        if (name.equals("padding")) {
+        if ("padding".equals(name)) {
             TypedArray a = r.obtainAttributes(attrs,
                     com.android.internal.R.styleable.ShapeDrawablePadding);
             setPadding(
@@ -315,7 +315,10 @@
         int color = mShapeState.mPaint.getColor();
         color = a.getColor(com.android.internal.R.styleable.ShapeDrawable_color, color);
         mShapeState.mPaint.setColor(color);
-            
+
+        boolean dither = a.getBoolean(com.android.internal.R.styleable.ShapeDrawable_dither, false);
+        mShapeState.mPaint.setDither(dither);
+
         setIntrinsicWidth((int)
                 a.getDimension(com.android.internal.R.styleable.ShapeDrawable_width, 0f));
         setIntrinsicHeight((int)
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index e5f7e62..f3c8f64 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -66,16 +66,17 @@
 
 // msgType in notifyCallback and dataCallback functions
 enum {
-    CAMERA_MSG_ERROR            = 0x001,
-    CAMERA_MSG_SHUTTER          = 0x002,
-    CAMERA_MSG_FOCUS            = 0x004,
-    CAMERA_MSG_ZOOM             = 0x008,
-    CAMERA_MSG_PREVIEW_FRAME    = 0x010,
-    CAMERA_MSG_VIDEO_FRAME      = 0x020,
-    CAMERA_MSG_POSTVIEW_FRAME   = 0x040,
-    CAMERA_MSG_RAW_IMAGE        = 0x080,
-    CAMERA_MSG_COMPRESSED_IMAGE = 0x100,
-    CAMERA_MSG_ALL_MSGS         = 0x1FF
+    CAMERA_MSG_ERROR            = 0x0001,
+    CAMERA_MSG_SHUTTER          = 0x0002,
+    CAMERA_MSG_FOCUS            = 0x0004,
+    CAMERA_MSG_ZOOM             = 0x0008,
+    CAMERA_MSG_PREVIEW_FRAME    = 0x0010,
+    CAMERA_MSG_VIDEO_FRAME      = 0x0020,
+    CAMERA_MSG_POSTVIEW_FRAME   = 0x0040,
+    CAMERA_MSG_RAW_IMAGE        = 0x0080,
+    CAMERA_MSG_COMPRESSED_IMAGE = 0x0100,
+    CAMERA_MSG_RAW_IMAGE_NOTIFY = 0x0200,
+    CAMERA_MSG_ALL_MSGS         = 0xFFFF
 };
 
 // cmdType in sendCommand functions
@@ -207,7 +208,7 @@
             status_t    cancelAutoFocus();
 
             // take a picture - picture returned from callback
-            status_t    takePicture();
+            status_t    takePicture(int msgType);
 
             // set preview/capture parameters - key/value pairs
             status_t    setParameters(const String8& params);
diff --git a/include/camera/ICamera.h b/include/camera/ICamera.h
index b2310a6..2344b3f 100644
--- a/include/camera/ICamera.h
+++ b/include/camera/ICamera.h
@@ -70,7 +70,7 @@
     virtual status_t        startRecording() = 0;
 
     // stop recording mode
-    virtual void            stopRecording() = 0;    
+    virtual void            stopRecording() = 0;
 
     // get recording state
     virtual bool            recordingEnabled() = 0;
@@ -84,8 +84,14 @@
     // cancel auto focus
     virtual status_t        cancelAutoFocus() = 0;
 
-    // take a picture
-    virtual status_t        takePicture() = 0;
+    /*
+     * take a picture.
+     * @param msgType the message type an application selectively turn on/off
+     * on a photo-by-photo basis. The supported message types are:
+     * CAMERA_MSG_SHUTTER, CAMERA_MSG_RAW_IMAGE, CAMERA_MSG_COMPRESSED_IMAGE,
+     * and CAMERA_MSG_POSTVIEW_FRAME. Any other message types will be ignored.
+     */
+    virtual status_t        takePicture(int msgType) = 0;
 
     // set preview/capture parameters - key/value pairs
     virtual status_t        setParameters(const String8& params) = 0;
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index 0bfb166..cce9129 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -54,6 +54,22 @@
     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
     virtual sp<IOMX>            getOMX() = 0;
+
+    // codecs usage tracking for the battery app
+    enum BatteryDataBits {
+        // tracking audio codec
+        kBatteryDataTrackAudio          = 1,
+        // tracking video codec
+        kBatteryDataTrackVideo          = 2,
+        // codec is started, otherwise codec is paused
+        kBatteryDataCodecStarted        = 4,
+        // tracking decoder (for media player),
+        // otherwise tracking encoder (for media recorder)
+        kBatteryDataTrackDecoder        = 8,
+    };
+
+    virtual void addBatteryData(uint32_t params) = 0;
+    virtual status_t pullBatteryData(Parcel* reply) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/stagefright/foundation/ABitReader.h b/include/media/stagefright/foundation/ABitReader.h
index 5135211..5510b12 100644
--- a/include/media/stagefright/foundation/ABitReader.h
+++ b/include/media/stagefright/foundation/ABitReader.h
@@ -31,6 +31,8 @@
     uint32_t getBits(size_t n);
     void skipBits(size_t n);
 
+    void putBits(uint32_t x, size_t n);
+
     size_t numBitsLeft() const;
 
     const uint8_t *data() const;
@@ -43,7 +45,6 @@
     size_t mNumBitsLeft;
 
     void fillReservoir();
-    void putBits(uint32_t x, size_t n);
 
     DISALLOW_EVIL_CONSTRUCTORS(ABitReader);
 };
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index c24c0db..f8d96cf 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -18,7 +18,6 @@
 #define ANDROID_REF_BASE_H
 
 #include <cutils/atomic.h>
-#include <utils/TextOutput.h>
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -27,6 +26,10 @@
 // ---------------------------------------------------------------------------
 namespace android {
 
+class TextOutput;
+TextOutput& printStrongPointer(TextOutput& to, const void* val);
+TextOutput& printWeakPointer(TextOutput& to, const void* val);
+
 template<typename T> class wp;
 
 // ---------------------------------------------------------------------------
@@ -427,8 +430,7 @@
 template <typename T>
 inline TextOutput& operator<<(TextOutput& to, const sp<T>& val)
 {
-    to << "sp<>(" << val.get() << ")";
-    return to;
+   return printStrongPointer(to, val.get());
 }
 
 // ---------------------------------------------------------------------------
@@ -585,8 +587,7 @@
 template <typename T>
 inline TextOutput& operator<<(TextOutput& to, const wp<T>& val)
 {
-    to << "wp<>(" << val.unsafe_get() << ")";
-    return to;
+    return printWeakPointer(to, val.unsafe_get());
 }
 
 }; // namespace android
diff --git a/libs/camera/Camera.cpp b/libs/camera/Camera.cpp
index 907f119..e288312 100644
--- a/libs/camera/Camera.cpp
+++ b/libs/camera/Camera.cpp
@@ -301,12 +301,12 @@
 }
 
 // take a picture
-status_t Camera::takePicture()
+status_t Camera::takePicture(int msgType)
 {
-    LOGV("takePicture");
+    LOGV("takePicture: 0x%x", msgType);
     sp <ICamera> c = mCamera;
     if (c == 0) return NO_INIT;
-    return c->takePicture();
+    return c->takePicture(msgType);
 }
 
 // set preview/capture parameters - key/value pairs
diff --git a/libs/camera/ICamera.cpp b/libs/camera/ICamera.cpp
index 0881d65..931b57d 100644
--- a/libs/camera/ICamera.cpp
+++ b/libs/camera/ICamera.cpp
@@ -223,11 +223,12 @@
     }
 
     // take a picture - returns an IMemory (ref-counted mmap)
-    status_t takePicture()
+    status_t takePicture(int msgType)
     {
-        LOGV("takePicture");
+        LOGV("takePicture: 0x%x", msgType);
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        data.writeInt32(msgType);
         remote()->transact(TAKE_PICTURE, data, &reply);
         status_t ret = reply.readInt32();
         return ret;
@@ -401,7 +402,8 @@
         case TAKE_PICTURE: {
             LOGV("TAKE_PICTURE");
             CHECK_INTERFACE(ICamera, data, reply);
-            reply->writeInt32(takePicture());
+            int msgType = data.readInt32();
+            reply->writeInt32(takePicture(msgType));
             return NO_ERROR;
         } break;
         case SET_PARAMETERS: {
diff --git a/libs/rs/java/Samples/AndroidManifest.xml b/libs/rs/java/Samples/AndroidManifest.xml
index 8dad161..c08a264 100644
--- a/libs/rs/java/Samples/AndroidManifest.xml
+++ b/libs/rs/java/Samples/AndroidManifest.xml
@@ -21,14 +21,5 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
-
-        <activity android:name="RsBench"
-                  android:label="RsBenchmark"
-                  android:theme="@android:style/Theme.Black.NoTitleBar">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
     </application>
 </manifest>
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 1dfedb3..2e6ea12 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -270,19 +270,23 @@
 
 Context::PushState::PushState(Context *con) {
     mRsc = con;
-    mFragment.set(con->getProgramFragment());
-    mVertex.set(con->getProgramVertex());
-    mStore.set(con->getProgramStore());
-    mRaster.set(con->getProgramRaster());
-    mFont.set(con->getFont());
+    if (con->mIsGraphicsContext) {
+        mFragment.set(con->getProgramFragment());
+        mVertex.set(con->getProgramVertex());
+        mStore.set(con->getProgramStore());
+        mRaster.set(con->getProgramRaster());
+        mFont.set(con->getFont());
+    }
 }
 
 Context::PushState::~PushState() {
-    mRsc->setProgramFragment(mFragment.get());
-    mRsc->setProgramVertex(mVertex.get());
-    mRsc->setProgramStore(mStore.get());
-    mRsc->setProgramRaster(mRaster.get());
-    mRsc->setFont(mFont.get());
+    if (mRsc->mIsGraphicsContext) {
+        mRsc->setProgramFragment(mFragment.get());
+        mRsc->setProgramVertex(mVertex.get());
+        mRsc->setProgramStore(mStore.get());
+        mRsc->setProgramRaster(mRaster.get());
+        mRsc->setFont(mFont.get());
+    }
 }
 
 
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
index 0bd1af4..f934eec 100644
--- a/libs/utils/RefBase.cpp
+++ b/libs/utils/RefBase.cpp
@@ -23,6 +23,7 @@
 #include <utils/KeyedVector.h>
 #include <utils/Log.h>
 #include <utils/threads.h>
+#include <utils/TextOutput.h>
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -530,5 +531,20 @@
 void RefBase::onLastWeakRef(const void* /*id*/)
 {
 }
-        
+
+// ---------------------------------------------------------------------------
+
+TextOutput& printStrongPointer(TextOutput& to, const void* val)
+{
+    to << "sp<>(" << val << ")";
+    return to;
+}
+
+TextOutput& printWeakPointer(TextOutput& to, const void* val)
+{
+    to << "wp<>(" << val << ")";
+    return to;
+}
+
+
 }; // namespace android
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index ee2c1e8..a027bc6 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -141,7 +141,9 @@
 
     private static boolean isWMAEnabled() {
         List<AudioDecoder> decoders = DecoderCapabilities.getAudioDecoders();
-        for (AudioDecoder decoder: decoders) {
+        int count = decoders.size();
+        for (int i = 0; i < count; i++) {
+            AudioDecoder decoder = decoders.get(i);
             if (decoder == AudioDecoder.AUDIO_DECODER_WMA) {
                 return true;
             }
@@ -149,6 +151,18 @@
         return false;
     }
 
+    private static boolean isWMVEnabled() {
+        List<VideoDecoder> decoders = DecoderCapabilities.getVideoDecoders();
+        int count = decoders.size();
+        for (int i = 0; i < count; i++) {
+            VideoDecoder decoder = decoders.get(i);
+            if (decoder == VideoDecoder.VIDEO_DECODER_WMV) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     static {
         addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg", MtpConstants.FORMAT_MP3);
         addFileType("M4A", FILE_TYPE_M4A, "audio/mp4", MtpConstants.FORMAT_MPEG);
@@ -184,8 +198,10 @@
         addFileType("WEBM", FILE_TYPE_MKV, "video/x-matroska");
         addFileType("TS", FILE_TYPE_MP2TS, "video/mp2ts");
 
-        addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv", MtpConstants.FORMAT_WMV);
-        addFileType("ASF", FILE_TYPE_ASF, "video/x-ms-asf");
+        if (isWMVEnabled()) {
+            addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv", MtpConstants.FORMAT_WMV);
+            addFileType("ASF", FILE_TYPE_ASF, "video/x-ms-asf");
+        }
 
         addFileType("JPG", FILE_TYPE_JPEG, "image/jpeg", MtpConstants.FORMAT_EXIF_JPEG);
         addFileType("JPEG", FILE_TYPE_JPEG, "image/jpeg", MtpConstants.FORMAT_EXIF_JPEG);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index f61ac0f..9c92ace 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1055,7 +1055,14 @@
     /**
      * Releases resources associated with this MediaPlayer object.
      * It is considered good practice to call this method when you're
-     * done using the MediaPlayer.
+     * done using the MediaPlayer. For instance, whenever the Activity
+     * of an application is paused, this method should be invoked to
+     * release the MediaPlayer object. In addition to unnecessary resources
+     * (such as memory and instances of codecs) being hold, failure to
+     * call this method immediately if a MediaPlayer object is no longer
+     * needed may also lead to continuous battery consumption for mobile
+     * devices, and playback failure if no multiple instances of the
+     * same codec is supported on a device.
      */
     public void release() {
         stayAwake(false);
@@ -1228,6 +1235,14 @@
     private native final void native_setup(Object mediaplayer_this);
     private native final void native_finalize();
 
+    /**
+     * @param reply Parcel with audio/video duration info for battery
+                    tracking usage
+     * @return The status code.
+     * {@hide}
+     */
+    public native static int native_pullBatteryData(Parcel reply);
+
     @Override
     protected void finalize() { native_finalize(); }
 
diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
index ad2bf95..e0df257 100644
--- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
+++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
@@ -3807,7 +3807,6 @@
         } catch (Throwable e) {
             // Allocating to new size with Fixed count
             try {
-                System.gc();
                 rgb888 = new int[thumbnailSize * MAX_THUMBNAIL_PERMITTED];
                 bitmaps = new Bitmap[MAX_THUMBNAIL_PERMITTED];
                 thumbnailCount = MAX_THUMBNAIL_PERMITTED;
diff --git a/media/java/android/media/videoeditor/MediaImageItem.java b/media/java/android/media/videoeditor/MediaImageItem.java
index 69088ed..4faa83a 100755
--- a/media/java/android/media/videoeditor/MediaImageItem.java
+++ b/media/java/android/media/videoeditor/MediaImageItem.java
@@ -197,7 +197,6 @@
             fl.close();
         }
         imageBitmap.recycle();
-        System.gc();
     }
 
     /*
diff --git a/media/java/android/media/videoeditor/Transition.java b/media/java/android/media/videoeditor/Transition.java
index 95f002c..3e8fe94 100755
--- a/media/java/android/media/videoeditor/Transition.java
+++ b/media/java/android/media/videoeditor/Transition.java
@@ -173,6 +173,7 @@
 
         mDurationMs = durationMs;
         invalidate();
+        mNativeHelper.setGeneratePreview(true);
     }
 
     /**
diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java
index d433887..fe734e1 100644
--- a/media/java/android/mtp/MtpServer.java
+++ b/media/java/android/mtp/MtpServer.java
@@ -54,6 +54,12 @@
         native_set_ptp_mode(usePtp);
     }
 
+    // Used to disable MTP by removing all storage units.
+    // This is done to disable access to file transfer when the device is locked.
+    public void setLocked(boolean locked) {
+        native_set_locked(locked);
+    }
+
     private native final void native_setup(MtpDatabase database, String storagePath,
             long reserveSpace);
     private native final void native_start();
@@ -61,4 +67,5 @@
     private native final void native_send_object_added(int handle);
     private native final void native_send_object_removed(int handle);
     private native final void native_set_ptp_mode(boolean usePtp);
+    private native final void native_set_locked(boolean locked);
 }
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 0884e35..ca54432 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -36,6 +36,8 @@
 #include "android_util_Binder.h"
 #include <binder/Parcel.h>
 #include <surfaceflinger/Surface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
 
 // ----------------------------------------------------------------------------
 
@@ -723,6 +725,21 @@
     process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL );
 }
 
+static jint
+android_media_MediaPlayer_pullBatteryData(JNIEnv *env, jobject thiz, jobject java_reply)
+{
+    sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player"));
+    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+    if (service.get() == NULL) {
+        jniThrowException(env, "java/lang/RuntimeException", "cannot get MediaPlayerService");
+        return UNKNOWN_ERROR;
+    }
+
+    Parcel *reply = parcelForJavaObject(env, java_reply);
+
+    return service->pullBatteryData(reply);
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
@@ -758,6 +775,7 @@
     {"setAudioSessionId",   "(I)V",                             (void *)android_media_MediaPlayer_set_audio_session_id},
     {"setAuxEffectSendLevel", "(F)V",                           (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
     {"attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer_attachAuxEffect},
+    {"native_pullBatteryData", "(Landroid/os/Parcel;)I",        (void *)android_media_MediaPlayer_pullBatteryData},
 };
 
 static const char* const kClassPathName = "android/media/MediaPlayer";
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index 3883fb2..e025ef1 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -35,6 +35,7 @@
 #include "private/android_filesystem_config.h"
 
 #include "MtpServer.h"
+#include "MtpStorage.h"
 
 using namespace android;
 
@@ -56,28 +57,47 @@
 private:
     MtpDatabase*    mDatabase;
     MtpServer*      mServer;
-    String8         mStoragePath;
-    uint64_t        mReserveSpace;
+    MtpStorage*     mStorage;
     Mutex           mMutex;
     bool            mUsePtp;
+    bool            mLocked;
     int             mFd;
 
 public:
-    MtpThread(MtpDatabase* database, const char* storagePath, uint64_t reserveSpace)
+    MtpThread(MtpDatabase* database, MtpStorage* storage)
         :   mDatabase(database),
             mServer(NULL),
-            mStoragePath(storagePath),
-            mReserveSpace(reserveSpace),
+            mStorage(storage),
+            mUsePtp(false),
+            mLocked(false),
             mFd(-1)
     {
     }
 
+    virtual ~MtpThread() {
+        delete mStorage;
+    }
+
     void setPtpMode(bool usePtp) {
         mMutex.lock();
         mUsePtp = usePtp;
         mMutex.unlock();
     }
 
+    void setLocked(bool locked) {
+        mMutex.lock();
+        if (locked != mLocked) {
+            if (mServer) {
+                if (locked)
+                    mServer->removeStorage(mStorage);
+                else
+                    mServer->addStorage(mStorage);
+            }
+            mLocked = locked;
+        }
+        mMutex.unlock();
+    }
+
     virtual bool threadLoop() {
         mMutex.lock();
         mFd = open("/dev/mtp_usb", O_RDWR);
@@ -86,7 +106,8 @@
                     (mUsePtp ? MTP_INTERFACE_MODE_PTP : MTP_INTERFACE_MODE_MTP));
 
             mServer = new MtpServer(mFd, mDatabase, AID_MEDIA_RW, 0664, 0775);
-            mServer->addStorage(mStoragePath, mReserveSpace);
+            if (!mLocked)
+                mServer->addStorage(mStorage);
 
             mMutex.unlock();
             mServer->run();
@@ -137,7 +158,8 @@
     const char *storagePathStr = env->GetStringUTFChars(storagePath, NULL);
 
     // create the thread and assign it to the smart pointer
-    sThread = new MtpThread(database, storagePathStr, reserveSpace);
+    MtpStorage* storage = new MtpStorage(MTP_FIRST_STORAGE_ID, storagePathStr, reserveSpace);
+    sThread = new MtpThread(database, storage);
 
     env->ReleaseStringUTFChars(storagePath, storagePathStr);
 #endif
@@ -195,6 +217,16 @@
 #endif
 }
 
+static void
+android_mtp_MtpServer_set_locked(JNIEnv *env, jobject thiz, jboolean locked)
+{
+#ifdef HAVE_ANDROID_OS
+    MtpThread *thread = sThread.get();
+    if (thread)
+        thread->setLocked(locked);
+#endif
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
@@ -205,6 +237,7 @@
     {"native_send_object_added",    "(I)V", (void *)android_mtp_MtpServer_send_object_added},
     {"native_send_object_removed",  "(I)V", (void *)android_mtp_MtpServer_send_object_removed},
     {"native_set_ptp_mode",         "(Z)V", (void *)android_mtp_MtpServer_set_ptp_mode},
+    {"native_set_locked",           "(Z)V", (void *)android_mtp_MtpServer_set_locked},
 };
 
 static const char* const kClassPathName = "android/mtp/MtpServer";
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 77199e1..17a0362 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -37,7 +37,9 @@
     DECODE_FD,
     CREATE_MEDIA_RECORDER,
     CREATE_METADATA_RETRIEVER,
-    GET_OMX
+    GET_OMX,
+    ADD_BATTERY_DATA,
+    PULL_BATTERY_DATA
 };
 
 class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
@@ -156,6 +158,19 @@
         remote()->transact(GET_OMX, data, &reply);
         return interface_cast<IOMX>(reply.readStrongBinder());
     }
+
+    virtual void addBatteryData(uint32_t params) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+        data.writeInt32(params);
+        remote()->transact(ADD_BATTERY_DATA, data, &reply);
+    }
+
+    virtual status_t pullBatteryData(Parcel* reply) {
+        Parcel data;
+        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+        return remote()->transact(PULL_BATTERY_DATA, data, reply);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService");
@@ -270,6 +285,17 @@
             reply->writeStrongBinder(omx->asBinder());
             return NO_ERROR;
         } break;
+        case ADD_BATTERY_DATA: {
+            CHECK_INTERFACE(IMediaPlayerService, data, reply);
+            uint32_t params = data.readInt32();
+            addBatteryData(params);
+            return NO_ERROR;
+        } break;
+        case PULL_BATTERY_DATA: {
+            CHECK_INTERFACE(IMediaPlayerService, data, reply);
+            pullBatteryData(reply);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index fd575fe..0100a17 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -298,6 +298,17 @@
         return INVALID_OPERATION;
     }
 
+    // It appears that if an invalid file descriptor is passed through
+    // binder calls, the server-side of the inter-process function call
+    // is skipped. As a result, the check at the server-side to catch
+    // the invalid file descritpor never gets invoked. This is to workaround
+    // this issue by checking the file descriptor first before passing
+    // it through binder call.
+    if (fd < 0) {
+        LOGE("Invalid file descriptor: %d", fd);
+        return BAD_VALUE;
+    }
+
     status_t ret = mMediaRecorder->setOutputFile(fd, offset, length);
     if (OK != ret) {
         LOGV("setOutputFile failed: %d", ret);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 60bdd62..8c6f76b 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -23,6 +23,7 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 #include <dirent.h>
 #include <unistd.h>
 
@@ -51,6 +52,8 @@
 #include <media/Metadata.h>
 #include <media/AudioTrack.h>
 
+#include <private/android_filesystem_config.h>
+
 #include "MediaRecorderClient.h"
 #include "MediaPlayerService.h"
 #include "MetadataRetrieverClient.h"
@@ -1762,4 +1765,93 @@
     return 0;
 }
 
+void MediaPlayerService::addBatteryData(uint32_t params)
+{
+    Mutex::Autolock lock(mLock);
+    int uid = IPCThreadState::self()->getCallingUid();
+    if (uid == AID_MEDIA) {
+        return;
+    }
+    int index = mBatteryData.indexOfKey(uid);
+    int32_t time = systemTime() / 1000000L;
+
+    if (index < 0) { // create a new entry for this UID
+        BatteryUsageInfo info;
+        info.audioTotalTime = 0;
+        info.videoTotalTime = 0;
+        info.audioLastTime = 0;
+        info.videoLastTime = 0;
+        info.refCount = 0;
+
+        mBatteryData.add(uid, info);
+    }
+
+    BatteryUsageInfo &info = mBatteryData.editValueFor(uid);
+
+    if (params & kBatteryDataCodecStarted) {
+        if (params & kBatteryDataTrackAudio) {
+            info.audioLastTime -= time;
+            info.refCount ++;
+        }
+        if (params & kBatteryDataTrackVideo) {
+            info.videoLastTime -= time;
+            info.refCount ++;
+        }
+    } else {
+        if (info.refCount == 0) {
+            LOGW("Battery track warning: refCount is already 0");
+            return;
+        } else if (info.refCount < 0) {
+            LOGE("Battery track error: refCount < 0");
+            mBatteryData.removeItem(uid);
+            return;
+        }
+
+        if (params & kBatteryDataTrackAudio) {
+            info.audioLastTime += time;
+            info.refCount --;
+        }
+        if (params & kBatteryDataTrackVideo) {
+            info.videoLastTime += time;
+            info.refCount --;
+        }
+
+        // no stream is being played by this UID
+        if (info.refCount == 0) {
+            info.audioTotalTime += info.audioLastTime;
+            info.audioLastTime = 0;
+            info.videoTotalTime += info.videoLastTime;
+            info.videoLastTime = 0;
+        }
+    }
+}
+
+status_t MediaPlayerService::pullBatteryData(Parcel* reply) {
+    Mutex::Autolock lock(mLock);
+    BatteryUsageInfo info;
+    int size = mBatteryData.size();
+
+    reply->writeInt32(size);
+    int i = 0;
+
+    while (i < size) {
+        info = mBatteryData.valueAt(i);
+
+        reply->writeInt32(mBatteryData.keyAt(i)); //UID
+        reply->writeInt32(info.audioTotalTime);
+        reply->writeInt32(info.videoTotalTime);
+
+        info.audioTotalTime = 0;
+        info.videoTotalTime = 0;
+
+        // remove the UID entry where no stream is being played
+        if (info.refCount <= 0) {
+            mBatteryData.removeItemsAt(i);
+            size --;
+            i --;
+        }
+        i++;
+    }
+    return NO_ERROR;
+}
 } // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 62f8ed6..9f41db0 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -204,7 +204,31 @@
 
             void                removeClient(wp<Client> client);
 
+    // For battery usage tracking purpose
+    struct BatteryUsageInfo {
+        // how many streams are being played by one UID
+        int     refCount;
+        // a temp variable to store the duration(ms) of audio codecs
+        // when we start a audio codec, we minus the system time from audioLastTime
+        // when we pause it, we add the system time back to the audioLastTime
+        // so after the pause, audioLastTime = pause time - start time
+        // if multiple audio streams are played (or recorded), then audioLastTime
+        // = the total playing time of all the streams
+        int32_t audioLastTime;
+        // when all the audio streams are being paused, we assign audioLastTime to
+        // this variable, so this value could be provided to the battery app
+        // in the next pullBatteryData call
+        int32_t audioTotalTime;
 
+        int32_t videoLastTime;
+        int32_t videoTotalTime;
+    };
+    KeyedVector<int, BatteryUsageInfo>    mBatteryData;
+
+    // Collect info of the codec usage from media player and media recorder
+    virtual void                addBatteryData(uint32_t params);
+    // API for the Battery app to pull the data of codecs usage
+    virtual status_t            pullBatteryData(Parcel* reply);
 private:
 
     class Client : public BnMediaPlayer {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 87fdbf2..e3dfabb 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -20,6 +20,10 @@
 
 #include "StagefrightRecorder.h"
 
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <media/IMediaPlayerService.h>
 #include <media/stagefright/AudioSource.h>
 #include <media/stagefright/AMRWriter.h>
 #include <media/stagefright/CameraSource.h>
@@ -46,9 +50,23 @@
 
 namespace android {
 
+// To collect the encoder usage for the battery app
+static void addBatteryData(uint32_t params) {
+    sp<IBinder> binder =
+        defaultServiceManager()->getService(String16("media.player"));
+    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+    CHECK(service.get() != NULL);
+
+    service->addBatteryData(params);
+}
+
+
 StagefrightRecorder::StagefrightRecorder()
     : mWriter(NULL), mWriterAux(NULL),
-      mOutputFd(-1), mOutputFdAux(-1) {
+      mOutputFd(-1), mOutputFdAux(-1),
+      mAudioSource(AUDIO_SOURCE_LIST_END),
+      mVideoSource(VIDEO_SOURCE_LIST_END),
+      mStarted(false) {
 
     LOGV("Constructor");
     reset();
@@ -745,30 +763,54 @@
         return UNKNOWN_ERROR;
     }
 
+    status_t status = OK;
+
     switch (mOutputFormat) {
         case OUTPUT_FORMAT_DEFAULT:
         case OUTPUT_FORMAT_THREE_GPP:
         case OUTPUT_FORMAT_MPEG_4:
-            return startMPEG4Recording();
+            status = startMPEG4Recording();
+            break;
 
         case OUTPUT_FORMAT_AMR_NB:
         case OUTPUT_FORMAT_AMR_WB:
-            return startAMRRecording();
+            status = startAMRRecording();
+            break;
 
         case OUTPUT_FORMAT_AAC_ADIF:
         case OUTPUT_FORMAT_AAC_ADTS:
-            return startAACRecording();
+            status = startAACRecording();
+            break;
 
         case OUTPUT_FORMAT_RTP_AVP:
-            return startRTPRecording();
+            status = startRTPRecording();
+            break;
 
         case OUTPUT_FORMAT_MPEG2TS:
-            return startMPEG2TSRecording();
+            status = startMPEG2TSRecording();
+            break;
 
         default:
             LOGE("Unsupported output file format: %d", mOutputFormat);
-            return UNKNOWN_ERROR;
+            status = UNKNOWN_ERROR;
+            break;
     }
+
+    if ((status == OK) && (!mStarted)) {
+        mStarted = true;
+
+        uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted;
+        if (mAudioSource != AUDIO_SOURCE_LIST_END) {
+            params |= IMediaPlayerService::kBatteryDataTrackAudio;
+        }
+        if (mVideoSource != VIDEO_SOURCE_LIST_END) {
+            params |= IMediaPlayerService::kBatteryDataTrackVideo;
+        }
+
+        addBatteryData(params);
+    }
+
+    return status;
 }
 
 sp<MediaSource> StagefrightRecorder::createAudioSource() {
@@ -1458,6 +1500,21 @@
         mWriterAux->pause();
     }
 
+    if (mStarted) {
+        mStarted = false;
+
+        uint32_t params = 0;
+        if (mAudioSource != AUDIO_SOURCE_LIST_END) {
+            params |= IMediaPlayerService::kBatteryDataTrackAudio;
+        }
+        if (mVideoSource != VIDEO_SOURCE_LIST_END) {
+            params |= IMediaPlayerService::kBatteryDataTrackVideo;
+        }
+
+        addBatteryData(params);
+    }
+
+
     return OK;
 }
 
@@ -1494,6 +1551,21 @@
         }
     }
 
+    if (mStarted) {
+        mStarted = false;
+
+        uint32_t params = 0;
+        if (mAudioSource != AUDIO_SOURCE_LIST_END) {
+            params |= IMediaPlayerService::kBatteryDataTrackAudio;
+        }
+        if (mVideoSource != VIDEO_SOURCE_LIST_END) {
+            params |= IMediaPlayerService::kBatteryDataTrackVideo;
+        }
+
+        addBatteryData(params);
+    }
+
+
     return err;
 }
 
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 72225db..2c440c1 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -107,6 +107,8 @@
     bool mIsMetaDataStoredInVideoBuffers;
     MediaProfiles *mEncoderProfiles;
 
+    bool mStarted;
+
     status_t setupMPEG4Recording(
         bool useSplitCameraSource,
         int outputFd,
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index b1d3630..1b63ab2 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -28,6 +28,8 @@
 #include "include/MPEG2TSExtractor.h"
 
 #include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/AudioPlayer.h>
@@ -155,8 +157,17 @@
             const AwesomeNativeWindowRenderer &);
 };
 
-////////////////////////////////////////////////////////////////////////////////
+// To collect the decoder usage
+void addBatteryData(uint32_t params) {
+    sp<IBinder> binder =
+        defaultServiceManager()->getService(String16("media.player"));
+    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+    CHECK(service.get() != NULL);
 
+    service->addBatteryData(params);
+}
+
+////////////////////////////////////////////////////////////////////////////////
 AwesomePlayer::AwesomePlayer()
     : mQueueStarted(false),
       mTimeSource(NULL),
@@ -379,6 +390,17 @@
             mDrmManagerClient = NULL;
     }
 
+    if (mFlags & PLAYING) {
+        uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
+        if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
+            params |= IMediaPlayerService::kBatteryDataTrackAudio;
+        }
+        if (mVideoSource != NULL) {
+            params |= IMediaPlayerService::kBatteryDataTrackVideo;
+        }
+        addBatteryData(params);
+    }
+
     if (mFlags & PREPARING) {
         mFlags |= PREPARE_CANCELLED;
         if (mConnectingDataSource != NULL) {
@@ -779,6 +801,16 @@
         seekTo_l(0);
     }
 
+    uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted
+        | IMediaPlayerService::kBatteryDataTrackDecoder;
+    if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
+        params |= IMediaPlayerService::kBatteryDataTrackAudio;
+    }
+    if (mVideoSource != NULL) {
+        params |= IMediaPlayerService::kBatteryDataTrackVideo;
+    }
+    addBatteryData(params);
+
     return OK;
 }
 
@@ -933,6 +965,16 @@
                 Playback::PAUSE, 0);
     }
 
+    uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
+    if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
+        params |= IMediaPlayerService::kBatteryDataTrackAudio;
+    }
+    if (mVideoSource != NULL) {
+        params |= IMediaPlayerService::kBatteryDataTrackVideo;
+    }
+
+    addBatteryData(params);
+
     return OK;
 }
 
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index e6fe618..3689557 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -277,7 +277,7 @@
         // this thread as read() will make a copy of this last frame and keep
         // returning it in the quick stop mode.
         Mutex::Autolock autoLock(mQuickStopLock);
-        CHECK_EQ(OK, mCamera->takePicture());
+        CHECK_EQ(OK, mCamera->takePicture(CAMERA_MSG_RAW_IMAGE));
         if (mQuickStop) {
             LOGV("threadTimeLapseEntry: Exiting due to mQuickStop = true");
             return;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index a973d7e..cf4cbe5 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1166,13 +1166,20 @@
 
         case FOURCC('d', '2', '6', '3'):
         {
-            // d263 contains fixed 7 bytes:
-            // vendor - 4 bytes
-            // version - 1 byte
-            // level - 1 byte
-            // profile - 1 byte
-            char buffer[7];
-            if (chunk_data_size != (off64_t) sizeof(buffer)) {
+            /*
+             * d263 contains a fixed 7 bytes part:
+             *   vendor - 4 bytes
+             *   version - 1 byte
+             *   level - 1 byte
+             *   profile - 1 byte
+             * optionally, "d263" box itself may contain a 16-byte
+             * bit rate box (bitr)
+             *   average bit rate - 4 bytes
+             *   max bit rate - 4 bytes
+             */
+            char buffer[23];
+            if (chunk_data_size != 7 &&
+                chunk_data_size != 23) {
                 LOGE("Incorrect D263 box size %lld", chunk_data_size);
                 return ERROR_MALFORMED;
             }
diff --git a/media/libstagefright/foundation/ABitReader.cpp b/media/libstagefright/foundation/ABitReader.cpp
index 24c8df8..f07dd4f 100644
--- a/media/libstagefright/foundation/ABitReader.cpp
+++ b/media/libstagefright/foundation/ABitReader.cpp
@@ -90,9 +90,7 @@
 }
 
 const uint8_t *ABitReader::data() const {
-    CHECK_EQ(mNumBitsLeft % 8, 0u);
-
-    return mData - mNumBitsLeft / 8;
+    return mData - (mNumBitsLeft + 7) / 8;
 }
 
 }  // namespace android
diff --git a/media/libstagefright/include/AMRExtractor.h b/media/libstagefright/include/AMRExtractor.h
index 589d837..4a1c827 100644
--- a/media/libstagefright/include/AMRExtractor.h
+++ b/media/libstagefright/include/AMRExtractor.h
@@ -18,6 +18,7 @@
 
 #define AMR_EXTRACTOR_H_
 
+#include <utils/Errors.h>
 #include <media/stagefright/MediaExtractor.h>
 
 namespace android {
diff --git a/media/libstagefright/include/MP3Extractor.h b/media/libstagefright/include/MP3Extractor.h
index 728980e..ef71b8f 100644
--- a/media/libstagefright/include/MP3Extractor.h
+++ b/media/libstagefright/include/MP3Extractor.h
@@ -18,6 +18,7 @@
 
 #define MP3_EXTRACTOR_H_
 
+#include <utils/Errors.h>
 #include <media/stagefright/MediaExtractor.h>
 
 namespace android {
diff --git a/media/libstagefright/include/OggExtractor.h b/media/libstagefright/include/OggExtractor.h
index a41f681..e97c8cd 100644
--- a/media/libstagefright/include/OggExtractor.h
+++ b/media/libstagefright/include/OggExtractor.h
@@ -18,6 +18,7 @@
 
 #define OGG_EXTRACTOR_H_
 
+#include <utils/Errors.h>
 #include <media/stagefright/MediaExtractor.h>
 
 namespace android {
diff --git a/media/libstagefright/include/WAVExtractor.h b/media/libstagefright/include/WAVExtractor.h
index 9de197f..ce1f33a 100644
--- a/media/libstagefright/include/WAVExtractor.h
+++ b/media/libstagefright/include/WAVExtractor.h
@@ -18,6 +18,7 @@
 
 #define WAV_EXTRACTOR_H_
 
+#include <utils/Errors.h>
 #include <media/stagefright/MediaExtractor.h>
 
 namespace android {
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h
index 0218755..afff824 100644
--- a/media/libstagefright/include/avc_utils.h
+++ b/media/libstagefright/include/avc_utils.h
@@ -19,6 +19,7 @@
 #define AVC_UTILS_H_
 
 #include <media/stagefright/foundation/ABuffer.h>
+#include <utils/Errors.h>
 
 namespace android {
 
diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
index 33c9d97..1f1c68b 100644
--- a/media/libstagefright/matroska/Android.mk
+++ b/media/libstagefright/matroska/Android.mk
@@ -2,11 +2,11 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=                 \
-        MatroskaExtractor.cpp     \
-        mkvparser.cpp             \
+        MatroskaExtractor.cpp
 
 LOCAL_C_INCLUDES:= \
-	$(JNI_H_INCLUDE) \
+        $(JNI_H_INCLUDE) \
+        $(TOP)/external/libvpx/mkvparser \
         $(TOP)/frameworks/base/include/media/stagefright/openmax \
 
 LOCAL_CFLAGS += -Wno-multichar
diff --git a/media/libstagefright/matroska/mkvparser.cpp b/media/libstagefright/matroska/mkvparser.cpp
deleted file mode 100644
index 7448d96..0000000
--- a/media/libstagefright/matroska/mkvparser.cpp
+++ /dev/null
@@ -1,4514 +0,0 @@
-// Copyright (c) 2010 The WebM project authors. All Rights Reserved.

-//

-// Use of this source code is governed by a BSD-style license

-// that can be found in the LICENSE file in the root of the source

-// tree. An additional intellectual property rights grant can be found

-// in the file PATENTS.  All contributing project authors may

-// be found in the AUTHORS file in the root of the source tree.

-

-#include "mkvparser.hpp"

-#include <cassert>

-#include <cstring>

-#include <new>

-//#include <windows.h>

-//#include "odbgstream.hpp"

-//using std::endl;

-

-mkvparser::IMkvReader::~IMkvReader()

-{

-}

-

-

-void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision)

-{

-    major = 1;

-    minor = 0;

-    build = 0;

-    revision = 4;

-}

-

-

-long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-    long long total, available;

-

-    long hr = pReader->Length(&total, &available);

-    assert(hr >= 0);

-    assert(pos < available);

-    assert((available - pos) >= 1);  //assume here max u-int len is 8

-

-    unsigned char b;

-

-    hr = pReader->Read(pos, 1, &b);

-    if (hr < 0)

-        return hr;

-

-    assert(hr == 0L);

-

-    if (b & 0x80)       //1000 0000

-    {

-        len = 1;

-        b &= 0x7F;      //0111 1111

-    }

-    else if (b & 0x40)  //0100 0000

-    {

-        len = 2;

-        b &= 0x3F;      //0011 1111

-    }

-    else if (b & 0x20)  //0010 0000

-    {

-        len = 3;

-        b &= 0x1F;      //0001 1111

-    }

-    else if (b & 0x10)  //0001 0000

-    {

-        len = 4;

-        b &= 0x0F;      //0000 1111

-    }

-    else if (b & 0x08)  //0000 1000

-    {

-        len = 5;

-        b &= 0x07;      //0000 0111

-    }

-    else if (b & 0x04)  //0000 0100

-    {

-        len = 6;

-        b &= 0x03;      //0000 0011

-    }

-    else if (b & 0x02)  //0000 0010

-    {

-        len = 7;

-        b &= 0x01;      //0000 0001

-    }

-    else

-    {

-        assert(b & 0x01);  //0000 0001

-        len = 8;

-        b = 0;             //0000 0000

-    }

-

-    assert((available - pos) >= len);

-

-    long long result = b;

-    ++pos;

-    for (long i = 1; i < len; ++i)

-    {

-        hr = pReader->Read(pos, 1, &b);

-

-        if (hr < 0)

-            return hr;

-

-        assert(hr == 0L);

-

-        result <<= 8;

-        result |= b;

-

-        ++pos;

-    }

-

-    return result;

-}

-

-

-long long mkvparser::GetUIntLength(

-    IMkvReader* pReader,

-    long long pos,

-    long& len)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-    long long total, available;

-

-    long hr = pReader->Length(&total, &available);

-    assert(hr >= 0);

-    assert(available <= total);

-

-    if (pos >= available)

-        return pos;  //too few bytes available

-

-    unsigned char b;

-

-    hr = pReader->Read(pos, 1, &b);

-

-    if (hr < 0)

-        return hr;

-

-    assert(hr == 0L);

-

-    if (b == 0)  //we can't handle u-int values larger than 8 bytes

-        return E_FILE_FORMAT_INVALID;

-

-    unsigned char m = 0x80;

-    len = 1;

-

-    while (!(b & m))

-    {

-        m >>= 1;

-        ++len;

-    }

-

-    return 0;  //success

-}

-

-

-long long mkvparser::SyncReadUInt(

-    IMkvReader* pReader,

-    long long pos,

-    long long stop,

-    long& len)

-{

-    assert(pReader);

-

-    if (pos >= stop)

-        return E_FILE_FORMAT_INVALID;

-

-    unsigned char b;

-

-    long hr = pReader->Read(pos, 1, &b);

-

-    if (hr < 0)

-        return hr;

-

-    if (hr != 0L)

-        return E_BUFFER_NOT_FULL;

-

-    if (b == 0)  //we can't handle u-int values larger than 8 bytes

-        return E_FILE_FORMAT_INVALID;

-

-    unsigned char m = 0x80;

-    len = 1;

-

-    while (!(b & m))

-    {

-        m >>= 1;

-        ++len;

-    }

-

-    if ((pos + len) > stop)

-        return E_FILE_FORMAT_INVALID;

-

-    long long result = b & (~m);

-    ++pos;

-

-    for (int i = 1; i < len; ++i)

-    {

-        hr = pReader->Read(pos, 1, &b);

-

-        if (hr < 0)

-            return hr;

-

-        if (hr != 0L)

-            return E_BUFFER_NOT_FULL;

-

-        result <<= 8;

-        result |= b;

-

-        ++pos;

-    }

-

-    return result;

-}

-

-

-long long mkvparser::UnserializeUInt(

-    IMkvReader* pReader,

-    long long pos,

-    long long size)

-{

-    assert(pReader);

-    assert(pos >= 0);

-    assert(size > 0);

-    assert(size <= 8);

-

-    long long result = 0;

-

-    for (long long i = 0; i < size; ++i)

-    {

-        unsigned char b;

-

-        const long hr = pReader->Read(pos, 1, &b);

-

-        if (hr < 0)

-            return hr;

-        result <<= 8;

-        result |= b;

-

-        ++pos;

-    }

-

-    return result;

-}

-

-

-float mkvparser::Unserialize4Float(

-    IMkvReader* pReader,

-    long long pos)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-    long long total, available;

-

-    long hr = pReader->Length(&total, &available);

-    assert(hr >= 0);

-    assert(available <= total);

-    assert((pos + 4) <= available);

-

-    float result;

-

-    unsigned char* const p = (unsigned char*)&result;

-    unsigned char* q = p + 4;

-

-    for (;;)

-    {

-        hr = pReader->Read(pos, 1, --q);

-        assert(hr == 0L);

-

-        if (q == p)

-            break;

-

-        ++pos;

-    }

-

-    return result;

-}

-

-

-double mkvparser::Unserialize8Double(

-    IMkvReader* pReader,

-    long long pos)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-    double result;

-

-    unsigned char* const p = (unsigned char*)&result;

-    unsigned char* q = p + 8;

-

-    for (;;)

-    {

-        const long hr = pReader->Read(pos, 1, --q);

-        assert(hr == 0L);

-

-        if (q == p)

-            break;

-

-        ++pos;

-    }

-

-    return result;

-}

-

-signed char mkvparser::Unserialize1SInt(

-    IMkvReader* pReader,

-    long long pos)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-    long long total, available;

-

-    long hr = pReader->Length(&total, &available);

-    assert(hr == 0);

-    assert(available <= total);

-    assert(pos < available);

-

-    signed char result;

-

-    hr = pReader->Read(pos, 1, (unsigned char*)&result);

-    assert(hr == 0);

-

-    return result;

-}

-

-short mkvparser::Unserialize2SInt(

-    IMkvReader* pReader,

-    long long pos)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-    long long total, available;

-

-    long hr = pReader->Length(&total, &available);

-    assert(hr >= 0);

-    assert(available <= total);

-    assert((pos + 2) <= available);

-

-    short result;

-

-    unsigned char* const p = (unsigned char*)&result;

-    unsigned char* q = p + 2;

-

-    for (;;)

-    {

-        hr = pReader->Read(pos, 1, --q);

-        assert(hr == 0L);

-

-        if (q == p)

-            break;

-

-        ++pos;

-    }

-

-    return result;

-}

-

-

-bool mkvparser::Match(

-    IMkvReader* pReader,

-    long long& pos,

-    unsigned long id_,

-    long long& val)

-

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-    long long total, available;

-

-    long hr = pReader->Length(&total, &available);

-    assert(hr >= 0);

-    assert(available <= total);

-

-    long len;

-

-    const long long id = ReadUInt(pReader, pos, len);

-    assert(id >= 0);

-    assert(len > 0);

-    assert(len <= 8);

-    assert((pos + len) <= available);

-

-    if ((unsigned long)id != id_)

-        return false;

-

-    pos += len;  //consume id

-

-    const long long size = ReadUInt(pReader, pos, len);

-    assert(size >= 0);

-    assert(size <= 8);

-    assert(len > 0);

-    assert(len <= 8);

-    assert((pos + len) <= available);

-

-    pos += len;  //consume length of size of payload

-

-    val = UnserializeUInt(pReader, pos, size);

-    assert(val >= 0);

-

-    pos += size;  //consume size of payload

-

-    return true;

-}

-

-bool mkvparser::Match(

-    IMkvReader* pReader,

-    long long& pos,

-    unsigned long id_,

-    char*& val)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-    long long total, available;

-

-    long hr = pReader->Length(&total, &available);

-    assert(hr >= 0);

-    assert(available <= total);

-

-    long len;

-

-    const long long id = ReadUInt(pReader, pos, len);

-    assert(id >= 0);

-    assert(len > 0);

-    assert(len <= 8);

-    assert((pos + len) <= available);

-

-    if ((unsigned long)id != id_)

-        return false;

-

-    pos += len;  //consume id

-

-    const long long size_ = ReadUInt(pReader, pos, len);

-    assert(size_ >= 0);

-    assert(len > 0);

-    assert(len <= 8);

-    assert((pos + len) <= available);

-

-    pos += len;  //consume length of size of payload

-    assert((pos + size_) <= available);

-

-    const size_t size = static_cast<size_t>(size_);

-    val = new char[size+1];

-

-    for (size_t i = 0; i < size; ++i)

-    {

-        char c;

-

-        hr = pReader->Read(pos + i, 1, (unsigned char*)&c);

-        assert(hr == 0L);

-

-        val[i] = c;

-

-        if (c == '\0')

-            break;

-

-    }

-

-    val[size] = '\0';

-    pos += size_;  //consume size of payload

-

-    return true;

-}

-

-bool mkvparser::Match(

-    IMkvReader* pReader,

-    long long& pos,

-    unsigned long id_,

-    unsigned char*& buf,

-    size_t& buflen)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-    long long total, available;

-

-    long hr = pReader->Length(&total, &available);

-    assert(hr >= 0);

-    assert(available <= total);

-

-    long len;

-    const long long id = ReadUInt(pReader, pos, len);

-    assert(id >= 0);

-    assert(len > 0);

-    assert(len <= 8);

-    assert((pos + len) <= available);

-

-    if ((unsigned long)id != id_)

-        return false;

-

-    pos += len;  //consume id

-

-    const long long size_ = ReadUInt(pReader, pos, len);

-    assert(size_ >= 0);

-    assert(len > 0);

-    assert(len <= 8);

-    assert((pos + len) <= available);

-

-    pos += len;  //consume length of size of payload

-    assert((pos + size_) <= available);

-

-    const long buflen_ = static_cast<long>(size_);

-

-    buf = new (std::nothrow) unsigned char[buflen_];

-    assert(buf);  //TODO

-

-    hr = pReader->Read(pos, buflen_, buf);

-    assert(hr == 0L);

-

-    buflen = buflen_;

-

-    pos += size_;  //consume size of payload

-    return true;

-}

-

-

-bool mkvparser::Match(

-    IMkvReader* pReader,

-    long long& pos,

-    unsigned long id_,

-    double& val)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-    long long total, available;

-

-    long hr = pReader->Length(&total, &available);

-    assert(hr >= 0);

-    assert(available <= total);

-    long idlen;

-    const long long id = ReadUInt(pReader, pos, idlen);

-    assert(id >= 0);  //TODO

-

-    if ((unsigned long)id != id_)

-        return false;

-

-    long sizelen;

-    const long long size = ReadUInt(pReader, pos + idlen, sizelen);

-

-    switch (size)

-    {

-        case 4:

-        case 8:

-            break;

-        default:

-            return false;

-    }

-

-    pos += idlen + sizelen;  //consume id and size fields

-    assert((pos + size) <= available);

-

-    if (size == 4)

-        val = Unserialize4Float(pReader, pos);

-    else

-    {

-        assert(size == 8);

-        val = Unserialize8Double(pReader, pos);

-    }

-

-    pos += size;  //consume size of payload

-

-    return true;

-}

-

-

-bool mkvparser::Match(

-    IMkvReader* pReader,

-    long long& pos,

-    unsigned long id_,

-    short& val)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-    long long total, available;

-

-    long hr = pReader->Length(&total, &available);

-    assert(hr >= 0);

-    assert(available <= total);

-

-    long len;

-    const long long id = ReadUInt(pReader, pos, len);

-    assert(id >= 0);

-    assert((pos + len) <= available);

-

-    if ((unsigned long)id != id_)

-        return false;

-

-    pos += len;  //consume id

-

-    const long long size = ReadUInt(pReader, pos, len);

-    assert(size <= 2);

-    assert((pos + len) <= available);

-

-    pos += len;  //consume length of size of payload

-    assert((pos + size) <= available);

-

-    //TODO:

-    // Generalize this to work for any size signed int

-    if (size == 1)

-        val = Unserialize1SInt(pReader, pos);

-    else

-        val = Unserialize2SInt(pReader, pos);

-

-    pos += size;  //consume size of payload

-

-    return true;

-}

-

-

-namespace mkvparser

-{

-

-EBMLHeader::EBMLHeader():

-    m_docType(NULL)

-{

-}

-

-EBMLHeader::~EBMLHeader()

-{

-    delete[] m_docType;

-}

-

-long long EBMLHeader::Parse(

-    IMkvReader* pReader,

-    long long& pos)

-{

-    assert(pReader);

-

-    long long total, available;

-

-    long hr = pReader->Length(&total, &available);

-

-    if (hr < 0)

-        return hr;

-

-    pos = 0;

-    long long end = (1024 < available)? 1024: available;

-

-    for (;;)

-    {

-        unsigned char b = 0;

-

-        while (pos < end)

-        {

-            hr = pReader->Read(pos, 1, &b);

-

-            if (hr < 0)

-                return hr;

-

-            if (b == 0x1A)

-                break;

-

-            ++pos;

-        }

-

-        if (b != 0x1A)

-        {

-            if ((pos >= 1024) ||

-                (available >= total) ||

-                ((total - available) < 5))

-                  return -1;

-

-            return available + 5;  //5 = 4-byte ID + 1st byte of size

-        }

-

-        if ((total - pos) < 5)

-            return E_FILE_FORMAT_INVALID;

-

-        if ((available - pos) < 5)

-            return pos + 5;  //try again later

-

-        long len;

-

-        const long long result = ReadUInt(pReader, pos, len);

-

-        if (result < 0)  //error

-            return result;

-

-        if (result == 0x0A45DFA3)  //ReadId masks-off length indicator bits

-        {

-            assert(len == 4);

-            pos += len;

-            break;

-        }

-

-        ++pos;  //throw away just the 0x1A byte, and try again

-    }

-

-    long len;

-    long long result = GetUIntLength(pReader, pos, len);

-

-    if (result < 0)  //error

-        return result;

-

-    if (result > 0)  //need more data

-        return result;

-

-    assert(len > 0);

-    assert(len <= 8);

-

-    if ((total -  pos) < len)

-        return E_FILE_FORMAT_INVALID;

-    if ((available - pos) < len)

-        return pos + len;  //try again later

-

-    result = ReadUInt(pReader, pos, len);

-

-    if (result < 0)  //error

-        return result;

-

-    pos += len;  //consume u-int

-

-    if ((total - pos) < result)

-        return E_FILE_FORMAT_INVALID;

-

-    if ((available - pos) < result)

-        return pos + result;

-

-    end = pos + result;

-

-    m_version = 1;

-    m_readVersion = 1;

-    m_maxIdLength = 4;

-    m_maxSizeLength = 8;

-    m_docTypeVersion = 1;

-    m_docTypeReadVersion = 1;

-

-    while (pos < end)

-    {

-        if (Match(pReader, pos, 0x0286, m_version))

-            ;

-        else if (Match(pReader, pos, 0x02F7, m_readVersion))

-            ;

-        else if (Match(pReader, pos, 0x02F2, m_maxIdLength))

-            ;

-        else if (Match(pReader, pos, 0x02F3, m_maxSizeLength))

-            ;

-        else if (Match(pReader, pos, 0x0282, m_docType))

-            ;

-        else if (Match(pReader, pos, 0x0287, m_docTypeVersion))

-            ;

-        else if (Match(pReader, pos, 0x0285, m_docTypeReadVersion))

-            ;

-        else

-        {

-            result = ReadUInt(pReader, pos, len);

-            assert(result > 0);

-            assert(len > 0);

-            assert(len <= 8);

-

-            pos += len;

-            assert(pos < end);

-

-            result = ReadUInt(pReader, pos, len);

-            assert(result >= 0);

-            assert(len > 0);

-            assert(len <= 8);

-

-            pos += len + result;

-            assert(pos <= end);

-        }

-    }

-

-    assert(pos == end);

-

-    return 0;

-}

-

-

-Segment::Segment(

-    IMkvReader* pReader,

-    long long start,

-    long long size) :

-    m_pReader(pReader),

-    m_start(start),

-    m_size(size),

-    m_pos(start),

-    m_pInfo(NULL),

-    m_pTracks(NULL),

-    m_pCues(NULL),

-    m_clusters(NULL),

-    m_clusterCount(0),

-    m_clusterPreloadCount(0),

-    m_clusterSize(0)

-{

-}

-

-

-Segment::~Segment()

-{

-    const long count = m_clusterCount + m_clusterPreloadCount;

-

-    Cluster** i = m_clusters;

-    Cluster** j = m_clusters + count;

-

-    while (i != j)

-    {

-        Cluster* const p = *i++;

-        assert(p);

-

-        delete p;

-    }

-

-    delete[] m_clusters;

-

-    delete m_pTracks;

-    delete m_pInfo;

-    delete m_pCues;

-}

-

-

-long long Segment::CreateInstance(

-    IMkvReader* pReader,

-    long long pos,

-    Segment*& pSegment)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-    pSegment = NULL;

-

-    long long total, available;

-

-    long hr = pReader->Length(&total, &available);

-    assert(hr >= 0);

-    assert(available <= total);

-

-    //I would assume that in practice this loop would execute

-    //exactly once, but we allow for other elements (e.g. Void)

-    //to immediately follow the EBML header.  This is fine for

-    //the source filter case (since the entire file is available),

-    //but in the splitter case over a network we should probably

-    //just give up early.  We could for example decide only to

-    //execute this loop a maximum of, say, 10 times.

-

-    while (pos < total)

-    {

-        //Read ID

-

-        long len;

-        long long result = GetUIntLength(pReader, pos, len);

-

-        if (result)  //error, or too few available bytes

-            return result;

-

-        if ((pos + len) > total)

-            return E_FILE_FORMAT_INVALID;

-

-        if ((pos + len) > available)

-            return pos + len;

-

-        //TODO: if we liberalize the behavior of ReadUInt, we can

-        //probably eliminate having to use GetUIntLength here.

-        const long long id = ReadUInt(pReader, pos, len);

-

-        if (id < 0)  //error

-            return id;

-

-        pos += len;  //consume ID

-

-        //Read Size

-

-        result = GetUIntLength(pReader, pos, len);

-

-        if (result)  //error, or too few available bytes

-            return result;

-

-        if ((pos + len) > total)

-            return E_FILE_FORMAT_INVALID;

-

-        if ((pos + len) > available)

-            return pos + len;

-

-        //TODO: if we liberalize the behavior of ReadUInt, we can

-        //probably eliminate having to use GetUIntLength here.

-        const long long size = ReadUInt(pReader, pos, len);

-

-        if (size < 0)

-            return size;

-

-        pos += len;  //consume length of size of element

-

-        //Pos now points to start of payload

-

-        if ((pos + size) > total)

-            return E_FILE_FORMAT_INVALID;

-

-        if (id == 0x08538067)  //Segment ID

-        {

-            pSegment = new  Segment(pReader, pos, size);

-            assert(pSegment);  //TODO

-

-            return 0;    //success

-        }

-

-        pos += size;  //consume payload

-    }

-

-    assert(pos == total);

-

-    pSegment = new Segment(pReader, pos, 0);

-    assert(pSegment);  //TODO

-

-    return 0;  //success (sort of)

-}

-

-

-long long Segment::ParseHeaders()

-{

-    //Outermost (level 0) segment object has been constructed,

-    //and pos designates start of payload.  We need to find the

-    //inner (level 1) elements.

-    long long total, available;

-

-    long hr = m_pReader->Length(&total, &available);

-    assert(hr >= 0);

-    assert(available <= total);

-

-    const long long stop = m_start + m_size;

-    assert(stop <= total);

-    assert(m_pos <= stop);

-

-    bool bQuit = false;

-

-    while ((m_pos < stop) && !bQuit)

-    {

-        long long pos = m_pos;

-

-        long len;

-        long long result = GetUIntLength(m_pReader, pos, len);

-

-        if (result)  //error, or too few available bytes

-            return result;

-

-        if ((pos + len) > stop)

-            return E_FILE_FORMAT_INVALID;

-

-        if ((pos + len) > available)

-            return pos + len;

-

-        const long long idpos = pos;

-        const long long id = ReadUInt(m_pReader, idpos, len);

-

-        if (id < 0)  //error

-            return id;

-

-        pos += len;  //consume ID

-

-        //Read Size

-        result = GetUIntLength(m_pReader, pos, len);

-

-        if (result)  //error, or too few available bytes

-            return result;

-

-        if ((pos + len) > stop)

-            return E_FILE_FORMAT_INVALID;

-

-        if ((pos + len) > available)

-            return pos + len;

-

-        const long long size = ReadUInt(m_pReader, pos, len);

-

-        if (size < 0)

-            return size;

-

-        pos += len;  //consume length of size of element

-

-        //Pos now points to start of payload

-

-        if ((pos + size) > stop)

-            return E_FILE_FORMAT_INVALID;

-

-        //We read EBML elements either in total or nothing at all.

-

-        if ((pos + size) > available)

-            return pos + size;

-

-        if (id == 0x0549A966)  //Segment Info ID

-        {

-            assert(m_pInfo == NULL);

-

-            m_pInfo = new SegmentInfo(this, pos, size);

-            assert(m_pInfo);  //TODO

-        }

-        else if (id == 0x0654AE6B)  //Tracks ID

-        {

-            assert(m_pTracks == NULL);

-

-            m_pTracks = new Tracks(this, pos, size);

-            assert(m_pTracks);  //TODO

-        }

-        else if (id == 0x0C53BB6B)  //Cues ID

-        {

-            if (m_pCues == NULL)

-            {

-                m_pCues = new Cues(this, pos, size);

-                assert(m_pCues);  //TODO

-            }

-        }

-        else if (id == 0x014D9B74)  //SeekHead ID

-        {

-            ParseSeekHead(pos, size);

-        }

-        else if (id == 0x0F43B675)  //Cluster ID

-        {

-            bQuit = true;

-        }

-

-        if (!bQuit)

-            m_pos = pos + size;  //consume payload

-    }

-

-    assert(m_pos <= stop);

-

-    if (m_pInfo == NULL)  //TODO: liberalize this behavior

-        return E_FILE_FORMAT_INVALID;

-

-    if (m_pTracks == NULL)

-        return E_FILE_FORMAT_INVALID;

-

-    return 0;  //success

-}

-

-

-#if 0

-long Segment::ParseCluster(Cluster*& pCluster, long long& pos_) const

-{

-    pCluster = NULL;

-    pos_ = -1;

-

-    const long long stop = m_start + m_size;

-    assert(m_pos <= stop);

-

-    long long pos = m_pos;

-    long long off = -1;

-

-    while (pos < stop)

-    {

-        long len;

-        const long long idpos = pos;

-

-        const long long id = SyncReadUInt(m_pReader, pos, stop, len);

-

-        if (id < 0)  //error

-            return static_cast<long>(id);

-

-        if (id == 0)

-            return E_FILE_FORMAT_INVALID;

-

-        pos += len;  //consume id

-        assert(pos < stop);

-

-        const long long size = SyncReadUInt(m_pReader, pos, stop, len);

-

-        if (size < 0)  //error

-            return static_cast<long>(size);

-

-        pos += len;  //consume size

-        assert(pos <= stop);

-

-        if (size == 0)  //weird

-            continue;

-

-        //pos now points to start of payload

-

-        pos += size;  //consume payload

-        assert(pos <= stop);

-

-        if (id == 0x0F43B675)  //Cluster ID

-        {

-            off = idpos - m_start;  // >= 0 means we found a cluster

-            break;

-        }

-    }

-

-    assert(pos <= stop);

-

-    //Indicate to caller how much of file has been consumed. This is

-    //used later in AddCluster to adjust the current parse position

-    //(the value cached in the segment object itself) to the

-    //file position value just past the cluster we parsed.

-

-    if (off < 0)  //we did not found any more clusters

-    {

-        pos_ = stop;  //pos_ >= 0 here means EOF (cluster is NULL)

-        return 0;     //TODO: confirm this return value

-    }

-

-    //We found a cluster.  Now read something, to ensure that it is

-    //fully loaded in the network cache.

-

-    if (pos >= stop)  //we parsed the entire segment

-    {

-        //We did find a cluster, but it was very last element in the segment.

-        //Our preference is that the loop above runs 1 1/2 times:

-        //the first pass finds the cluster, and the second pass

-        //finds the element the follows the cluster.  In this case, however,

-        //we reached the end of the file without finding another element,

-        //so we didn't actually read anything yet associated with "end of the

-        //cluster".  And we must perform an actual read, in order

-        //to guarantee that all of the data that belongs to this

-        //cluster has been loaded into the network cache.  So instead

-        //of reading the next element that follows the cluster, we

-        //read the last byte of the cluster (which is also the last

-        //byte in the file).

-

-        //Read the last byte of the file. (Reading 0 bytes at pos

-        //might work too -- it would depend on how the reader is

-        //implemented.  Here we take the more conservative approach,

-        //since this makes fewer assumptions about the network

-        //reader abstraction.)

-

-        unsigned char b;

-

-        const int result = m_pReader->Read(pos - 1, 1, &b);

-        assert(result == 0);

-

-        pos_ = stop;

-    }

-    else

-    {

-        long len;

-        const long long idpos = pos;

-

-        const long long id = SyncReadUInt(m_pReader, pos, stop, len);

-

-        if (id < 0)  //error

-            return static_cast<long>(id);

-

-        if (id == 0)

-            return E_BUFFER_NOT_FULL;

-

-        pos += len;  //consume id

-        assert(pos < stop);

-

-        const long long size = SyncReadUInt(m_pReader, pos, stop, len);

-

-        if (size < 0)  //error

-            return static_cast<long>(size);

-

-        pos_ = idpos;

-    }

-

-    //We found a cluster, and it has been completely loaded into the

-    //network cache.  (We can guarantee this because we actually read

-    //the EBML tag that follows the cluster, or, if we reached EOF,

-    //because we actually read the last byte of the cluster).

-

-    Segment* const this_ = const_cast<Segment*>(this);

-

-    pCluster = Cluster::Parse(this_, m_clusterCount, off);

-    assert(pCluster);

-    assert(pCluster->m_index == m_clusterCount);

-

-    return 0;

-}

-

-

-bool Segment::AddCluster(Cluster* pCluster, long long pos)

-{

-    assert(pos >= m_start);

-

-    const long long stop = m_start + m_size;

-    assert(pos <= stop);

-

-    if (pCluster)

-    {

-        AppendCluster(pCluster);

-        assert(m_clusters);

-        assert(m_clusterSize > pCluster->m_index);

-        assert(m_clusters[pCluster->m_index] == pCluster);

-    }

-

-    m_pos = pos;  //m_pos >= stop is now we know we have all clusters

-

-    return (pos >= stop);

-}

-#endif

-

-

-long Segment::LoadCluster()

-{

-    const long long stop = m_start + m_size;

-

-    while (m_pos < stop)

-    {

-        long long pos = m_pos;

-

-        long len;

-

-        long long result = GetUIntLength(m_pReader, pos, len);

-

-        if (result < 0)  //error

-            return static_cast<long>(result);

-

-        if ((pos + len) > stop)

-            return E_FILE_FORMAT_INVALID;

-

-        const long long idpos = pos;

-        const long long id = ReadUInt(m_pReader, idpos, len);

-

-        if (id < 0)  //error

-            return static_cast<long>(id);

-

-        pos += len;  //consume ID

-

-        //Read Size

-        result = GetUIntLength(m_pReader, pos, len);

-

-        if (result < 0)  //error

-            return static_cast<long>(result);

-

-        if ((pos + len) > stop)

-            return E_FILE_FORMAT_INVALID;

-

-        const long long size = ReadUInt(m_pReader, pos, len);

-

-        if (size < 0)  //error

-            return static_cast<long>(size);

-

-        pos += len;  //consume length of size of element

-

-        if (size == 0)  //weird

-        {

-            m_pos = pos;

-            continue;

-        }

-

-        //Pos now points to start of payload

-

-        if ((pos + size) > stop)

-            return E_FILE_FORMAT_INVALID;

-

-        if (id == 0x0C53BB6B)  //Cues ID

-        {

-            if (m_pCues == NULL)

-            {

-                m_pCues = new Cues(this, pos, size);

-                assert(m_pCues);  //TODO

-            }

-

-            m_pos = pos + size;  //consume payload

-            continue;

-        }

-

-        if (id != 0x0F43B675)  //Cluster ID

-        {

-            m_pos = pos + size;  //consume payload

-            continue;

-        }

-

-        const long idx = m_clusterCount;

-        const long long idoff = idpos - m_start;

-

-        if (m_clusterPreloadCount > 0)

-        {

-            assert(idx < m_clusterSize);

-

-            Cluster* const pCluster = m_clusters[idx];

-            assert(pCluster);

-            assert(pCluster->m_index < 0);

-

-            const long long off_ = pCluster->m_pos;

-            assert(off_);

-

-            const long long off = off_ * ((off_ >= 0) ? 1 : -1);

-            assert(idoff <= off);

-

-            if (idoff == off)  //cluster has been preloaded already

-            {

-                pCluster->m_index = idx;

-                ++m_clusterCount;

-                --m_clusterPreloadCount;

-

-                m_pos = pos + size;  //consume payload

-                break;

-            }

-        }

-

-        Cluster* const pCluster = Cluster::Parse(this, idx, idoff);

-        assert(pCluster);

-        assert(pCluster->m_index == idx);

-

-        AppendCluster(pCluster);

-        assert(m_clusters);

-        assert(idx < m_clusterSize);

-        assert(m_clusters[idx] == pCluster);

-

-        m_pos = pos + size;  //consume payload

-        break;

-    }

-

-    assert(m_pos <= stop);

-    return 0;

-}

-

-

-void Segment::AppendCluster(Cluster* pCluster)

-{

-    assert(pCluster);

-    assert(pCluster->m_index >= 0);

-

-    const long count = m_clusterCount + m_clusterPreloadCount;

-

-    long& size = m_clusterSize;

-    assert(size >= count);

-

-    const long idx = pCluster->m_index;

-    assert(idx == m_clusterCount);

-

-    if (count >= size)

-    {

-        long n;

-

-        if (size > 0)

-            n = 2 * size;

-        else if (m_pInfo == 0)

-            n = 2048;

-        else

-        {

-            const long long ns = m_pInfo->GetDuration();

-

-            if (ns <= 0)

-                n = 2048;

-            else

-            {

-                const long long sec = (ns + 999999999LL) / 1000000000LL;

-                n = static_cast<long>(sec);

-            }

-        }

-

-        Cluster** const qq = new Cluster*[n];

-        Cluster** q = qq;

-

-        Cluster** p = m_clusters;

-        Cluster** const pp = p + count;

-

-        while (p != pp)

-            *q++ = *p++;

-

-        delete[] m_clusters;

-

-        m_clusters = qq;

-        size = n;

-    }

-

-    if (m_clusterPreloadCount > 0)

-    {

-        assert(m_clusters);

-

-        Cluster** const p = m_clusters + m_clusterCount;

-        assert(*p);

-        assert((*p)->m_index < 0);

-

-        Cluster** q = p + m_clusterPreloadCount;

-        assert(q < (m_clusters + size));

-

-        for (;;)

-        {

-            Cluster** const qq = q - 1;

-            assert((*qq)->m_index < 0);

-

-            *q = *qq;

-            q = qq;

-

-            if (q == p)

-                break;

-        }

-    }

-

-    m_clusters[idx] = pCluster;

-    ++m_clusterCount;

-}

-

-

-void Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx)

-{

-    assert(pCluster);

-    assert(pCluster->m_index < 0);

-    assert(idx >= m_clusterCount);

-

-    const long count = m_clusterCount + m_clusterPreloadCount;

-

-    long& size = m_clusterSize;

-    assert(size >= count);

-

-    if (count >= size)

-    {

-        long n;

-

-        if (size > 0)

-            n = 2 * size;

-        else if (m_pInfo == 0)

-            n = 2048;

-        else

-        {

-            const long long ns = m_pInfo->GetDuration();

-

-            if (ns <= 0)

-                n = 2048;

-            else

-            {

-                const long long sec = (ns + 999999999LL) / 1000000000LL;

-                n = static_cast<long>(sec);

-            }

-        }

-

-        Cluster** const qq = new Cluster*[n];

-        Cluster** q = qq;

-

-        Cluster** p = m_clusters;

-        Cluster** const pp = p + count;

-

-        while (p != pp)

-            *q++ = *p++;

-

-        delete[] m_clusters;

-

-        m_clusters = qq;

-        size = n;

-    }

-

-    assert(m_clusters);

-

-    Cluster** const p = m_clusters + idx;

-

-    Cluster** q = m_clusters + count;

-    assert(q >= p);

-    assert(q < (m_clusters + size));

-

-    while (q > p)

-    {

-        Cluster** const qq = q - 1;

-        assert((*qq)->m_index < 0);

-

-        *q = *qq;

-        q = qq;

-    }

-

-    m_clusters[idx] = pCluster;

-    ++m_clusterPreloadCount;

-}

-

-

-long Segment::Load()

-{

-    assert(m_clusters == NULL);

-    assert(m_clusterSize == 0);

-    assert(m_clusterCount == 0);

-

-    //Outermost (level 0) segment object has been constructed,

-    //and pos designates start of payload.  We need to find the

-    //inner (level 1) elements.

-    const long long stop = m_start + m_size;

-

-#ifdef _DEBUG  //TODO: this is really Microsoft-specific

-    {

-        long long total, available;

-

-        long hr = m_pReader->Length(&total, &available);

-        assert(hr >= 0);

-        assert(available >= total);

-        assert(stop <= total);

-    }

-#endif

-

-    while (m_pos < stop)

-    {

-        long long pos = m_pos;

-

-        long len;

-

-        long long result = GetUIntLength(m_pReader, pos, len);

-

-        if (result < 0)  //error

-            return static_cast<long>(result);

-

-        if ((pos + len) > stop)

-            return E_FILE_FORMAT_INVALID;

-

-        const long long idpos = pos;

-        const long long id = ReadUInt(m_pReader, idpos, len);

-

-        if (id < 0)  //error

-            return static_cast<long>(id);

-

-        pos += len;  //consume ID

-

-        //Read Size

-        result = GetUIntLength(m_pReader, pos, len);

-

-        if (result < 0)  //error

-            return static_cast<long>(result);

-

-        if ((pos + len) > stop)

-            return E_FILE_FORMAT_INVALID;

-

-        const long long size = ReadUInt(m_pReader, pos, len);

-

-        if (size < 0)  //error

-            return static_cast<long>(size);

-

-        pos += len;  //consume length of size of element

-

-        //Pos now points to start of payload

-

-        if ((pos + size) > stop)

-            return E_FILE_FORMAT_INVALID;

-

-        if (id == 0x0F43B675)  //Cluster ID

-        {

-            const long idx = m_clusterCount;

-            const long long off = idpos - m_start;

-

-            Cluster* const pCluster = Cluster::Parse(this, idx, off);

-            assert(pCluster);

-            assert(pCluster->m_index == idx);

-

-            AppendCluster(pCluster);

-            assert(m_clusters);

-            assert(m_clusterSize > idx);

-            assert(m_clusters[idx] == pCluster);

-        }

-        else if (id == 0x0C53BB6B)  //Cues ID

-        {

-            assert(m_pCues == NULL);

-

-            m_pCues = new Cues(this, pos, size);

-            assert(m_pCues);  //TODO

-        }

-        else if (id == 0x0549A966)  //SegmentInfo ID

-        {

-            assert(m_pInfo == NULL);

-

-            m_pInfo = new  SegmentInfo(this, pos, size);

-            assert(m_pInfo);

-        }

-        else if (id == 0x0654AE6B)  //Tracks ID

-        {

-            assert(m_pTracks == NULL);

-

-            m_pTracks = new Tracks(this, pos, size);

-            assert(m_pTracks);  //TODO

-        }

-

-        m_pos = pos + size;  //consume payload

-    }

-

-    assert(m_pos >= stop);

-

-    if (m_pInfo == NULL)

-        return E_FILE_FORMAT_INVALID;  //TODO: ignore this case?

-

-    if (m_pTracks == NULL)

-        return E_FILE_FORMAT_INVALID;

-

-    if (m_clusters == NULL)  //TODO: ignore this case?

-        return E_FILE_FORMAT_INVALID;

-

-    //TODO: decide whether we require Cues element

-    //if (m_pCues == NULL)

-    //   return E_FILE_FORMAT_INVALID;

-

-    return 0;

-}

-

-

-void Segment::ParseSeekHead(long long start, long long size_)

-{

-    long long pos = start;

-    const long long stop = start + size_;

-

-    while (pos < stop)

-    {

-        long len;

-

-        const long long id = ReadUInt(m_pReader, pos, len);

-        assert(id >= 0);  //TODO

-        assert((pos + len) <= stop);

-

-        pos += len;  //consume ID

-

-        const long long size = ReadUInt(m_pReader, pos, len);

-        assert(size >= 0);

-        assert((pos + len) <= stop);

-

-        pos += len;  //consume Size field

-        assert((pos + size) <= stop);

-

-        if (id == 0x0DBB)  //SeekEntry ID

-            ParseSeekEntry(pos, size);

-

-        pos += size;  //consume payload

-        assert(pos <= stop);

-    }

-

-    assert(pos == stop);

-}

-

-

-void Segment::ParseCues(long long off)

-{

-    if (m_pCues)

-        return;

-

-    //odbgstream os;

-    //os << "Segment::ParseCues (begin)" << endl;

-

-    long long pos = m_start + off;

-    const long long stop = m_start + m_size;

-

-    long len;

-

-    long long result = GetUIntLength(m_pReader, pos, len);

-    assert(result == 0);

-    assert((pos + len) <= stop);

-

-    const long long idpos = pos;

-

-    const long long id = ReadUInt(m_pReader, idpos, len);

-    assert(id == 0x0C53BB6B);  //Cues ID

-

-    pos += len;  //consume ID

-    assert(pos < stop);

-

-    //Read Size

-

-    result = GetUIntLength(m_pReader, pos, len);

-    assert(result == 0);

-    assert((pos + len) <= stop);

-

-    const long long size = ReadUInt(m_pReader, pos, len);

-    assert(size >= 0);

-

-    pos += len;  //consume length of size of element

-    assert((pos + size) <= stop);

-

-    //Pos now points to start of payload

-

-    m_pCues = new Cues(this, pos, size);

-    assert(m_pCues);  //TODO

-

-    //os << "Segment::ParseCues (end)" << endl;

-}

-

-

-void Segment::ParseSeekEntry(

-   long long start,

-   long long size_)

-{

-    long long pos = start;

-

-    const long long stop = start + size_;

-

-    long len;

-

-    const long long seekIdId = ReadUInt(m_pReader, pos, len);

-    //seekIdId;

-    assert(seekIdId == 0x13AB);  //SeekID ID

-    assert((pos + len) <= stop);

-

-    pos += len;  //consume id

-

-    const long long seekIdSize = ReadUInt(m_pReader, pos, len);

-    assert(seekIdSize >= 0);

-    assert((pos + len) <= stop);

-

-    pos += len;  //consume size

-

-    const long long seekId = ReadUInt(m_pReader, pos, len);  //payload

-    assert(seekId >= 0);

-    assert(len == seekIdSize);

-    assert((pos + len) <= stop);

-

-    pos += seekIdSize;  //consume payload

-

-    const long long seekPosId = ReadUInt(m_pReader, pos, len);

-    //seekPosId;

-    assert(seekPosId == 0x13AC);  //SeekPos ID

-    assert((pos + len) <= stop);

-

-    pos += len;  //consume id

-

-    const long long seekPosSize = ReadUInt(m_pReader, pos, len);

-    assert(seekPosSize >= 0);

-    assert((pos + len) <= stop);

-

-    pos += len;  //consume size

-    assert((pos + seekPosSize) <= stop);

-

-    const long long seekOff = UnserializeUInt(m_pReader, pos, seekPosSize);

-    assert(seekOff >= 0);

-    assert(seekOff < m_size);

-

-    pos += seekPosSize;  //consume payload

-    assert(pos == stop);

-

-    const long long seekPos = m_start + seekOff;

-    assert(seekPos < (m_start + m_size));

-

-    if (seekId == 0x0C53BB6B)  //Cues ID

-        ParseCues(seekOff);

-}

-

-

-Cues::Cues(Segment* pSegment, long long start_, long long size_) :

-    m_pSegment(pSegment),

-    m_start(start_),

-    m_size(size_),

-    m_cue_points(NULL),

-    m_count(0),

-    m_preload_count(0),

-    m_pos(start_)

-{

-}

-

-

-Cues::~Cues()

-{

-    const size_t n = m_count + m_preload_count;

-

-    CuePoint** p = m_cue_points;

-    CuePoint** const q = p + n;

-

-    while (p != q)

-    {

-        CuePoint* const pCP = *p++;

-        assert(pCP);

-

-        delete pCP;

-    }

-

-    delete[] m_cue_points;

-}

-

-

-void Cues::Init() const

-{

-    if (m_cue_points)

-        return;

-

-    assert(m_count == 0);

-    assert(m_preload_count == 0);

-

-    IMkvReader* const pReader = m_pSegment->m_pReader;

-

-    const long long stop = m_start + m_size;

-    long long pos = m_start;

-

-    size_t cue_points_size = 0;

-

-    while (pos < stop)

-    {

-        const long long idpos = pos;

-

-        long len;

-

-        const long long id = ReadUInt(pReader, pos, len);

-        assert(id >= 0);  //TODO

-        assert((pos + len) <= stop);

-

-        pos += len;  //consume ID

-

-        const long long size = ReadUInt(pReader, pos, len);

-        assert(size >= 0);

-        assert((pos + len) <= stop);

-

-        pos += len;  //consume Size field

-        assert((pos + size) <= stop);

-

-        if (id == 0x3B)  //CuePoint ID

-            PreloadCuePoint(cue_points_size, idpos);

-

-        pos += size;  //consume payload

-        assert(pos <= stop);

-    }

-}

-

-

-void Cues::PreloadCuePoint(

-    size_t& cue_points_size,

-    long long pos) const

-{

-    assert(m_count == 0);

-

-    if (m_preload_count >= cue_points_size)

-    {

-        size_t n;

-

-        if (cue_points_size > 0)

-            n = static_cast<size_t>(2 * cue_points_size);

-        else

-        {

-            const SegmentInfo* const pInfo = m_pSegment->GetInfo();

-

-            if (pInfo == NULL)

-                n = 2048;

-            else

-            {

-                const long long ns = pInfo->GetDuration();

-

-                if (ns <= 0)

-                    n = 2048;

-                else

-                {

-                    const long long sec = (ns + 999999999LL) / 1000000000LL;

-                    n = static_cast<size_t>(sec);

-                }

-            }

-        }

-

-        CuePoint** const qq = new CuePoint*[n];

-        CuePoint** q = qq;  //beginning of target

-

-        CuePoint** p = m_cue_points;                //beginning of source

-        CuePoint** const pp = p + m_preload_count;  //end of source

-

-        while (p != pp)

-            *q++ = *p++;

-

-        delete[] m_cue_points;

-

-        m_cue_points = qq;

-        cue_points_size = n;

-    }

-

-    CuePoint* const pCP = new CuePoint(m_preload_count, pos);

-    m_cue_points[m_preload_count++] = pCP;

-}

-

-

-bool Cues::LoadCuePoint() const

-{

-    //odbgstream os;

-    //os << "Cues::LoadCuePoint" << endl;

-

-    const long long stop = m_start + m_size;

-

-    if (m_pos >= stop)

-        return false;  //nothing else to do

-

-    Init();

-

-    IMkvReader* const pReader = m_pSegment->m_pReader;

-

-    while (m_pos < stop)

-    {

-        const long long idpos = m_pos;

-

-        long len;

-

-        const long long id = ReadUInt(pReader, m_pos, len);

-        assert(id >= 0);  //TODO

-        assert((m_pos + len) <= stop);

-

-        m_pos += len;  //consume ID

-

-        const long long size = ReadUInt(pReader, m_pos, len);

-        assert(size >= 0);

-        assert((m_pos + len) <= stop);

-

-        m_pos += len;  //consume Size field

-        assert((m_pos + size) <= stop);

-

-        if (id != 0x3B)  //CuePoint ID

-        {

-            m_pos += size;  //consume payload

-            assert(m_pos <= stop);

-

-            continue;

-        }

-

-        assert(m_preload_count > 0);

-

-        CuePoint* const pCP = m_cue_points[m_count];

-        assert(pCP);

-        assert((pCP->GetTimeCode() >= 0) || (-pCP->GetTimeCode() == idpos));

-

-        pCP->Load(pReader);

-        ++m_count;

-        --m_preload_count;

-

-        m_pos += size;  //consume payload

-        assert(m_pos <= stop);

-

-        break;

-    }

-

-    return (m_pos < stop);

-}

-

-

-bool Cues::Find(

-    long long time_ns,

-    const Track* pTrack,

-    const CuePoint*& pCP,

-    const CuePoint::TrackPosition*& pTP) const

-{

-    assert(time_ns >= 0);

-    assert(pTrack);

-

-    LoadCuePoint();

-

-    assert(m_cue_points);

-    assert(m_count > 0);

-

-    CuePoint** const ii = m_cue_points;

-    CuePoint** i = ii;

-

-    CuePoint** const jj = ii + m_count + m_preload_count;

-    CuePoint** j = jj;

-

-    pCP = *i;

-    assert(pCP);

-

-    if (time_ns <= pCP->GetTime(m_pSegment))

-    {

-        pTP = pCP->Find(pTrack);

-        return (pTP != NULL);

-    }

-

-    IMkvReader* const pReader = m_pSegment->m_pReader;

-

-    while (i < j)

-    {

-        //INVARIANT:

-        //[ii, i) <= time_ns

-        //[i, j)  ?

-        //[j, jj) > time_ns

-

-        CuePoint** const k = i + (j - i) / 2;

-        assert(k < jj);

-

-        CuePoint* const pCP = *k;

-        assert(pCP);

-

-        pCP->Load(pReader);

-

-        const long long t = pCP->GetTime(m_pSegment);

-

-        if (t <= time_ns)

-            i = k + 1;

-        else

-            j = k;

-

-        assert(i <= j);

-    }

-

-    assert(i == j);

-    assert(i <= jj);

-    assert(i > ii);

-

-    pCP = *--i;

-    assert(pCP);

-    assert(pCP->GetTime(m_pSegment) <= time_ns);

-

-    //TODO: here and elsewhere, it's probably not correct to search

-    //for the cue point with this time, and then search for a matching

-    //track.  In principle, the matching track could be on some earlier

-    //cue point, and with our current algorithm, we'd miss it.  To make

-    //this bullet-proof, we'd need to create a secondary structure,

-    //with a list of cue points that apply to a track, and then search

-    //that track-based structure for a matching cue point.

-

-    pTP = pCP->Find(pTrack);

-    return (pTP != NULL);

-}

-

-

-#if 0

-bool Cues::FindNext(

-    long long time_ns,

-    const Track* pTrack,

-    const CuePoint*& pCP,

-    const CuePoint::TrackPosition*& pTP) const

-{

-    pCP = 0;

-    pTP = 0;

-

-    if (m_count == 0)

-        return false;

-

-    assert(m_cue_points);

-

-    const CuePoint* const* const ii = m_cue_points;

-    const CuePoint* const* i = ii;

-

-    const CuePoint* const* const jj = ii + m_count;

-    const CuePoint* const* j = jj;

-

-    while (i < j)

-    {

-        //INVARIANT:

-        //[ii, i) <= time_ns

-        //[i, j)  ?

-        //[j, jj) > time_ns

-

-        const CuePoint* const* const k = i + (j - i) / 2;

-        assert(k < jj);

-

-        pCP = *k;

-        assert(pCP);

-

-        const long long t = pCP->GetTime(m_pSegment);

-

-        if (t <= time_ns)

-            i = k + 1;

-        else

-            j = k;

-

-        assert(i <= j);

-    }

-

-    assert(i == j);

-    assert(i <= jj);

-

-    if (i >= jj)  //time_ns is greater than max cue point

-        return false;

-

-    pCP = *i;

-    assert(pCP);

-    assert(pCP->GetTime(m_pSegment) > time_ns);

-

-    pTP = pCP->Find(pTrack);

-    return (pTP != NULL);

-}

-#endif

-

-

-const CuePoint* Cues::GetFirst() const

-{

-    LoadCuePoint();  //init cues

-

-    const size_t count = m_count + m_preload_count;

-

-    if (count == 0)  //weird

-        return NULL;

-

-    CuePoint* const* const pp = m_cue_points;

-    assert(pp);

-

-    CuePoint* const pCP = pp[0];

-    assert(pCP);

-    assert(pCP->GetTimeCode() >= 0);

-

-    return pCP;

-}

-

-

-const CuePoint* Cues::GetLast() const

-{

-    LoadCuePoint();  //init cues

-

-    const size_t count = m_count + m_preload_count;

-

-    if (count == 0)  //weird

-        return NULL;

-

-    const size_t index = count - 1;

-

-    CuePoint* const* const pp = m_cue_points;

-    assert(pp);

-

-    CuePoint* const pCP = pp[index];

-    assert(pCP);

-

-    pCP->Load(m_pSegment->m_pReader);

-    assert(pCP->GetTimeCode() >= 0);

-

-    return pCP;

-}

-

-

-const CuePoint* Cues::GetNext(const CuePoint* pCurr) const

-{

-    if (pCurr == NULL)

-        return NULL;

-

-    assert(pCurr->GetTimeCode() >= 0);

-    assert(m_cue_points);

-    assert(m_count >= 1);

-

-    const size_t count = m_count + m_preload_count;

-

-    size_t index = pCurr->m_index;

-    assert(index < count);

-

-    CuePoint* const* const pp = m_cue_points;

-    assert(pp);

-    assert(pp[index] == pCurr);

-

-    ++index;

-

-    if (index >= count)

-        return NULL;

-

-    CuePoint* const pNext = pp[index];

-    assert(pNext);

-

-    pNext->Load(m_pSegment->m_pReader);

-

-    return pNext;

-}

-

-

-const BlockEntry* Cues::GetBlock(

-    const CuePoint* pCP,

-    const CuePoint::TrackPosition* pTP) const

-{

-    if (pCP == NULL)

-        return NULL;

-

-    if (pTP == NULL)

-        return NULL;

-

-    return m_pSegment->GetBlock(*pCP, *pTP);

-}

-

-

-const BlockEntry* Segment::GetBlock(

-    const CuePoint& cp,

-    const CuePoint::TrackPosition& tp)

-{

-    Cluster** const ii = m_clusters;

-    Cluster** i = ii;

-

-    const long count = m_clusterCount + m_clusterPreloadCount;

-

-    Cluster** const jj = ii + count;

-    Cluster** j = jj;

-

-    while (i < j)

-    {

-        //INVARIANT:

-        //[ii, i) < pTP->m_pos

-        //[i, j) ?

-        //[j, jj)  > pTP->m_pos

-

-        Cluster** const k = i + (j - i) / 2;

-        assert(k < jj);

-

-        Cluster* const pCluster = *k;

-        assert(pCluster);

-

-        const long long pos_ = pCluster->m_pos;

-        assert(pos_);

-

-        const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);

-

-        if (pos < tp.m_pos)

-            i = k + 1;

-        else if (pos > tp.m_pos)

-            j = k;

-        else

-            return pCluster->GetEntry(cp, tp);

-    }

-

-    assert(i == j);

-

-    Cluster* const pCluster = Cluster::Parse(this, -1, tp.m_pos);

-    const ptrdiff_t idx = i - m_clusters;

-

-    PreloadCluster(pCluster, idx);

-    assert(m_clusters);

-    assert(m_clusterPreloadCount > 0);

-    assert(m_clusters[idx] == pCluster);

-

-    return pCluster->GetEntry(cp, tp);

-}

-

-

-

-CuePoint::CuePoint(size_t idx, long long pos) :

-    m_index(idx),

-    m_timecode(-1 * pos),

-    m_track_positions(NULL),

-    m_track_positions_count(0)

-{

-    assert(pos > 0);

-}

-

-

-CuePoint::~CuePoint()

-{

-    delete[] m_track_positions;

-}

-

-

-void CuePoint::Load(IMkvReader* pReader)

-{

-    //odbgstream os;

-    //os << "CuePoint::Load(begin): timecode=" << m_timecode << endl;

-

-    if (m_timecode >= 0)  //already loaded

-        return;

-

-    assert(m_track_positions == NULL);

-    assert(m_track_positions_count == 0);

-

-    long long pos_ = -m_timecode;

-

-    long long stop;

-

-    {

-        long len;

-

-        const long long id = ReadUInt(pReader, pos_, len);

-        assert(id == 0x3B);  //CuePoint ID

-        //assert((pos + len) <= stop);

-

-        pos_ += len;  //consume ID

-

-        const long long size = ReadUInt(pReader, pos_, len);

-        assert(size >= 0);

-        //assert((pos + len) <= stop);

-

-        pos_ += len;  //consume Size field

-        //assert((pos + size) <= stop);

-

-        //pos_ now points to start of payload

-

-        stop = pos_ + size;

-    }

-

-    long long pos = pos_;

-

-    //First count number of track positions

-

-    while (pos < stop)

-    {

-        long len;

-

-        const long long id = ReadUInt(pReader, pos, len);

-        assert(id >= 0);  //TODO

-        assert((pos + len) <= stop);

-

-        pos += len;  //consume ID

-

-        const long long size = ReadUInt(pReader, pos, len);

-        assert(size >= 0);

-        assert((pos + len) <= stop);

-

-        pos += len;  //consume Size field

-        assert((pos + size) <= stop);

-

-        if (id == 0x33)  //CueTime ID

-            m_timecode = UnserializeUInt(pReader, pos, size);

-

-        else if (id == 0x37) //CueTrackPosition(s) ID

-            ++m_track_positions_count;

-

-        pos += size;  //consume payload

-        assert(pos <= stop);

-    }

-

-    assert(m_timecode >= 0);

-    assert(m_track_positions_count > 0);

-

-    //os << "CuePoint::Load(cont'd): idpos=" << idpos

-    //   << " timecode=" << m_timecode

-    //   << endl;

-

-    m_track_positions = new TrackPosition[m_track_positions_count];

-

-    //Now parse track positions

-

-    TrackPosition* p = m_track_positions;

-    pos = pos_;

-

-    while (pos < stop)

-    {

-        long len;

-

-        const long long id = ReadUInt(pReader, pos, len);

-        assert(id >= 0);  //TODO

-        assert((pos + len) <= stop);

-

-        pos += len;  //consume ID

-

-        const long long size = ReadUInt(pReader, pos, len);

-        assert(size >= 0);

-        assert((pos + len) <= stop);

-

-        pos += len;  //consume Size field

-        assert((pos + size) <= stop);

-

-        if (id == 0x37) //CueTrackPosition(s) ID

-        {

-            TrackPosition& tp = *p++;

-            tp.Parse(pReader, pos, size);

-        }

-

-        pos += size;  //consume payload

-        assert(pos <= stop);

-    }

-

-    assert(size_t(p - m_track_positions) == m_track_positions_count);

-}

-

-

-

-void CuePoint::TrackPosition::Parse(

-    IMkvReader* pReader,

-    long long start_,

-    long long size_)

-{

-    const long long stop = start_ + size_;

-    long long pos = start_;

-

-    m_track = -1;

-    m_pos = -1;

-    m_block = 1;  //default

-

-    while (pos < stop)

-    {

-        long len;

-

-        const long long id = ReadUInt(pReader, pos, len);

-        assert(id >= 0);  //TODO

-        assert((pos + len) <= stop);

-

-        pos += len;  //consume ID

-

-        const long long size = ReadUInt(pReader, pos, len);

-        assert(size >= 0);

-        assert((pos + len) <= stop);

-

-        pos += len;  //consume Size field

-        assert((pos + size) <= stop);

-

-        if (id == 0x77)  //CueTrack ID

-            m_track = UnserializeUInt(pReader, pos, size);

-

-        else if (id == 0x71)  //CueClusterPos ID

-            m_pos = UnserializeUInt(pReader, pos, size);

-

-        else if (id == 0x1378)  //CueBlockNumber

-            m_block = UnserializeUInt(pReader, pos, size);

-

-        pos += size;  //consume payload

-        assert(pos <= stop);

-    }

-

-    assert(m_pos >= 0);

-    //assert(m_track > 0);

-    //assert(m_block > 0);

-}

-

-

-const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const

-{

-    assert(pTrack);

-

-    const long long n = pTrack->GetNumber();

-

-    const TrackPosition* i = m_track_positions;

-    const TrackPosition* const j = i + m_track_positions_count;

-

-    while (i != j)

-    {

-        const TrackPosition& p = *i++;

-

-        if (p.m_track == n)

-            return &p;

-    }

-

-    return NULL;  //no matching track number found

-}

-

-

-long long CuePoint::GetTimeCode() const

-{

-    return m_timecode;

-}

-

-long long CuePoint::GetTime(Segment* pSegment) const

-{

-    assert(pSegment);

-    assert(m_timecode >= 0);

-

-    const SegmentInfo* const pInfo = pSegment->GetInfo();

-    assert(pInfo);

-

-    const long long scale = pInfo->GetTimeCodeScale();

-    assert(scale >= 1);

-

-    const long long time = scale * m_timecode;

-

-    return time;

-}

-

-

-long long Segment::Unparsed() const

-{

-    const long long stop = m_start + m_size;

-

-    const long long result = stop - m_pos;

-    assert(result >= 0);

-

-    return result;

-}

-

-

-Cluster* Segment::GetFirst()

-{

-    if ((m_clusters == NULL) || (m_clusterCount <= 0))

-       return &m_eos;

-

-    Cluster* const pCluster = m_clusters[0];

-    assert(pCluster);

-

-    return pCluster;

-}

-

-

-Cluster* Segment::GetLast()

-{

-    if ((m_clusters == NULL) || (m_clusterCount <= 0))

-        return &m_eos;

-

-    const long idx = m_clusterCount - 1;

-

-    Cluster* const pCluster = m_clusters[idx];

-    assert(pCluster);

-

-    return pCluster;

-}

-

-

-unsigned long Segment::GetCount() const

-{

-    return m_clusterCount;

-}

-

-

-Cluster* Segment::GetNext(const Cluster* pCurr)

-{

-    assert(pCurr);

-    assert(pCurr != &m_eos);

-    assert(m_clusters);

-

-    long idx =  pCurr->m_index;

-

-    if (idx >= 0)

-    {

-        assert(m_clusterCount > 0);

-        assert(idx < m_clusterCount);

-        assert(pCurr == m_clusters[idx]);

-

-        ++idx;

-

-        if (idx >= m_clusterCount)

-            return &m_eos;  //caller will LoadCluster as desired

-

-        Cluster* const pNext = m_clusters[idx];

-        assert(pNext);

-        assert(pNext->m_index >= 0);

-        assert(pNext->m_index == idx);

-

-        return pNext;

-    }

-

-    assert(m_clusterPreloadCount > 0);

-

-    const long long off_ = pCurr->m_pos;

-    const long long off = off_ * ((off_ < 0) ? -1 : 1);

-

-    long long pos = m_start + off;

-    const long long stop = m_start + m_size;  //end of segment

-

-    {

-        long len;

-

-        long long result = GetUIntLength(m_pReader, pos, len);

-        assert(result == 0);  //TODO

-        assert((pos + len) <= stop);  //TODO

-

-        const long long id = ReadUInt(m_pReader, pos, len);

-        assert(id == 0x0F43B675);  //Cluster ID   //TODO

-

-        pos += len;  //consume ID

-

-        //Read Size

-        result = GetUIntLength(m_pReader, pos, len);

-        assert(result == 0);  //TODO

-        assert((pos + len) <= stop);  //TODO

-

-        const long long size = ReadUInt(m_pReader, pos, len);

-        assert(size > 0);  //TODO

-        assert((pCurr->m_size <= 0) || (pCurr->m_size == size));

-

-        pos += len;  //consume length of size of element

-        assert((pos + size) <= stop);  //TODO

-

-        //Pos now points to start of payload

-

-        pos += size;  //consume payload

-    }

-

-    long long off_next = 0;

-

-    while (pos < stop)

-    {

-        long len;

-

-        long long result = GetUIntLength(m_pReader, pos, len);

-        assert(result == 0);  //TODO

-        assert((pos + len) <= stop);  //TODO

-

-        const long long idpos = pos;  //pos of next (potential) cluster

-

-        const long long id = ReadUInt(m_pReader, idpos, len);

-        assert(id > 0);  //TODO

-

-        pos += len;  //consume ID

-

-        //Read Size

-        result = GetUIntLength(m_pReader, pos, len);

-        assert(result == 0);  //TODO

-        assert((pos + len) <= stop);  //TODO

-

-        const long long size = ReadUInt(m_pReader, pos, len);

-        assert(size >= 0);  //TODO

-

-        pos += len;  //consume length of size of element

-        assert((pos + size) <= stop);  //TODO

-

-        //Pos now points to start of payload

-

-        if (size == 0)  //weird

-            continue;

-

-        if (id == 0x0F43B675)  //Cluster ID

-        {

-            off_next = idpos - m_start;

-            break;

-        }

-

-        pos += size;  //consume payload

-    }

-

-    if (off_next <= 0)

-        return 0;

-

-    Cluster** const ii = m_clusters + m_clusterCount;

-    Cluster** i = ii;

-

-    Cluster** const jj = ii + m_clusterPreloadCount;

-    Cluster** j = jj;

-

-    while (i < j)

-    {

-        //INVARIANT:

-        //[0, i) < pos_next

-        //[i, j) ?

-        //[j, jj)  > pos_next

-

-        Cluster** const k = i + (j - i) / 2;

-        assert(k < jj);

-

-        Cluster* const pNext = *k;

-        assert(pNext);

-        assert(pNext->m_index < 0);

-

-        const long long pos_ = pNext->m_pos;

-        assert(pos_);

-

-        pos = pos_ * ((pos_ < 0) ? -1 : 1);

-

-        if (pos < off_next)

-            i = k + 1;

-        else if (pos > off_next)

-            j = k;

-        else

-            return pNext;

-    }

-

-    assert(i == j);

-

-    Cluster* const pNext = Cluster::Parse(this, -1, off_next);

-    const ptrdiff_t idx_next = i - m_clusters;  //insertion position

-

-    PreloadCluster(pNext, idx_next);

-    assert(m_clusters);

-    assert(idx_next < m_clusterSize);

-    assert(m_clusters[idx_next] == pNext);

-

-    return pNext;

-}

-

-

-Cluster* Segment::FindCluster(long long time_ns)

-{

-    if ((m_clusters == NULL) || (m_clusterCount <= 0))

-        return &m_eos;

-

-    {

-        Cluster* const pCluster = m_clusters[0];

-        assert(pCluster);

-        assert(pCluster->m_index == 0);

-

-        if (time_ns <= pCluster->GetTime())

-            return pCluster;

-    }

-

-    //Binary search of cluster array

-

-    long i = 0;

-    long j = m_clusterCount;

-

-    while (i < j)

-    {

-        //INVARIANT:

-        //[0, i) <= time_ns

-        //[i, j) ?

-        //[j, m_clusterCount)  > time_ns

-

-        const long k = i + (j - i) / 2;

-        assert(k < m_clusterCount);

-

-        Cluster* const pCluster = m_clusters[k];

-        assert(pCluster);

-        assert(pCluster->m_index == k);

-

-        const long long t = pCluster->GetTime();

-

-        if (t <= time_ns)

-            i = k + 1;

-        else

-            j = k;

-

-        assert(i <= j);

-    }

-

-    assert(i == j);

-    assert(i > 0);

-    assert(i <= m_clusterCount);

-

-    const long k = i - 1;

-

-    Cluster* const pCluster = m_clusters[k];

-    assert(pCluster);

-    assert(pCluster->m_index == k);

-    assert(pCluster->GetTime() <= time_ns);

-

-    return pCluster;

-}

-

-

-const BlockEntry* Segment::Seek(

-    long long time_ns,

-    const Track* pTrack)

-{

-    assert(pTrack);

-

-    if ((m_clusters == NULL) || (m_clusterCount <= 0))

-        return pTrack->GetEOS();

-

-    Cluster** const i = m_clusters;

-    assert(i);

-

-    {

-        Cluster* const pCluster = *i;

-        assert(pCluster);

-        assert(pCluster->m_index == 0);  //m_clusterCount > 0

-        assert(pCluster->m_pSegment == this);

-

-        if (time_ns <= pCluster->GetTime())

-            return pCluster->GetEntry(pTrack);

-    }

-

-    Cluster** const j = i + m_clusterCount;

-

-    if (pTrack->GetType() == 2)  //audio

-    {

-        //TODO: we could decide to use cues for this, as we do for video.

-        //But we only use it for video because looking around for a keyframe

-        //can get expensive.  Audio doesn't require anything special so a

-        //straight cluster search is good enough (we assume).

-

-        Cluster** lo = i;

-        Cluster** hi = j;

-

-        while (lo < hi)

-        {

-            //INVARIANT:

-            //[i, lo) <= time_ns

-            //[lo, hi) ?

-            //[hi, j)  > time_ns

-

-            Cluster** const mid = lo + (hi - lo) / 2;

-            assert(mid < hi);

-

-            Cluster* const pCluster = *mid;

-            assert(pCluster);

-            assert(pCluster->m_index == long(mid - m_clusters));

-            assert(pCluster->m_pSegment == this);

-

-            const long long t = pCluster->GetTime();

-

-            if (t <= time_ns)

-                lo = mid + 1;

-            else

-                hi = mid;

-

-            assert(lo <= hi);

-        }

-

-        assert(lo == hi);

-        assert(lo > i);

-        assert(lo <= j);

-

-        Cluster* const pCluster = *--lo;

-        assert(pCluster);

-        assert(pCluster->GetTime() <= time_ns);

-

-        return pCluster->GetEntry(pTrack);

-    }

-

-    assert(pTrack->GetType() == 1);  //video

-

-    Cluster** lo = i;

-    Cluster** hi = j;

-

-    while (lo < hi)

-    {

-        //INVARIANT:

-        //[i, lo) <= time_ns

-        //[lo, hi) ?

-        //[hi, j)  > time_ns

-

-        Cluster** const mid = lo + (hi - lo) / 2;

-        assert(mid < hi);

-

-        Cluster* const pCluster = *mid;

-        assert(pCluster);

-

-        const long long t = pCluster->GetTime();

-

-        if (t <= time_ns)

-            lo = mid + 1;

-        else

-            hi = mid;

-

-        assert(lo <= hi);

-    }

-

-    assert(lo == hi);

-    assert(lo > i);

-    assert(lo <= j);

-

-    Cluster* pCluster = *--lo;

-    assert(pCluster);

-    assert(pCluster->GetTime() <= time_ns);

-

-    {

-        const BlockEntry* const pBlockEntry = pCluster->GetEntry(pTrack);

-        assert(pBlockEntry);

-

-        if (!pBlockEntry->EOS())  //found a keyframe

-        {

-            const Block* const pBlock = pBlockEntry->GetBlock();

-            assert(pBlock);

-

-            //TODO: this isn't necessarily the keyframe we want,

-            //since there might another keyframe on this same

-            //cluster with a greater timecode that but that is

-            //still less than the requested time.  For now we

-            //simply return the first keyframe we find.

-

-            if (pBlock->GetTime(pCluster) <= time_ns)

-                return pBlockEntry;

-        }

-    }

-

-    const VideoTrack* const pVideo = static_cast<const VideoTrack*>(pTrack);

-

-    while (lo != i)

-    {

-        pCluster = *--lo;

-        assert(pCluster);

-        assert(pCluster->GetTime() <= time_ns);

-

-        const BlockEntry* const pBlockEntry = pCluster->GetMaxKey(pVideo);

-        assert(pBlockEntry);

-

-        if (!pBlockEntry->EOS())

-            return pBlockEntry;

-    }

-

-    //weird: we're on the first cluster, but no keyframe found

-    //should never happen but we must return something anyway

-

-    return pTrack->GetEOS();

-}

-

-

-#if 0

-bool Segment::SearchCues(

-    long long time_ns,

-    Track* pTrack,

-    Cluster*& pCluster,

-    const BlockEntry*& pBlockEntry,

-    const CuePoint*& pCP,

-    const CuePoint::TrackPosition*& pTP)

-{

-    if (pTrack->GetType() != 1)  //not video

-        return false;  //TODO: for now, just handle video stream

-

-    if (m_pCues == NULL)

-        return false;

-

-    if (!m_pCues->Find(time_ns, pTrack, pCP, pTP))

-        return false;  //weird

-

-    assert(pCP);

-    assert(pTP);

-    assert(pTP->m_track == pTrack->GetNumber());

-

-    //We have the cue point and track position we want,

-    //so we now need to search for the cluster having

-    //the indicated position.

-

-    return GetCluster(pCP, pTP, pCluster, pBlockEntry);

-}

-#endif

-

-

-Tracks* Segment::GetTracks() const

-{

-    return m_pTracks;

-}

-

-

-const SegmentInfo* Segment::GetInfo() const

-{

-    return m_pInfo;

-}

-

-

-const Cues* Segment::GetCues() const

-{

-    return m_pCues;

-}

-

-

-long long Segment::GetDuration() const

-{

-    assert(m_pInfo);

-    return m_pInfo->GetDuration();

-}

-

-

-SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_) :

-    m_pSegment(pSegment),

-    m_start(start),

-    m_size(size_),

-    m_pMuxingAppAsUTF8(NULL),

-    m_pWritingAppAsUTF8(NULL),

-    m_pTitleAsUTF8(NULL)

-{

-    IMkvReader* const pReader = m_pSegment->m_pReader;

-

-    long long pos = start;

-    const long long stop = start + size_;

-

-    m_timecodeScale = 1000000;

-    m_duration = -1;

-

-    while (pos < stop)

-    {

-        if (Match(pReader, pos, 0x0AD7B1, m_timecodeScale))

-            assert(m_timecodeScale > 0);

-

-        else if (Match(pReader, pos, 0x0489, m_duration))

-            assert(m_duration >= 0);

-

-        else if (Match(pReader, pos, 0x0D80, m_pMuxingAppAsUTF8))   //[4D][80]

-            assert(m_pMuxingAppAsUTF8);

-

-        else if (Match(pReader, pos, 0x1741, m_pWritingAppAsUTF8))  //[57][41]

-            assert(m_pWritingAppAsUTF8);

-

-        else if (Match(pReader, pos, 0x3BA9, m_pTitleAsUTF8))       //[7B][A9]

-            assert(m_pTitleAsUTF8);

-

-        else

-        {

-            long len;

-

-            const long long id = ReadUInt(pReader, pos, len);

-            //id;

-            assert(id >= 0);

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume id

-            assert((stop - pos) > 0);

-

-            const long long size = ReadUInt(pReader, pos, len);

-            assert(size >= 0);

-            assert((pos + len) <= stop);

-

-            pos += len + size;  //consume size and payload

-            assert(pos <= stop);

-        }

-    }

-

-    assert(pos == stop);

-}

-

-SegmentInfo::~SegmentInfo()

-{

-    if (m_pMuxingAppAsUTF8)

-    {

-        delete[] m_pMuxingAppAsUTF8;

-        m_pMuxingAppAsUTF8 = NULL;

-    }

-

-    if (m_pWritingAppAsUTF8)

-    {

-        delete[] m_pWritingAppAsUTF8;

-        m_pWritingAppAsUTF8 = NULL;

-    }

-

-    if (m_pTitleAsUTF8)

-    {

-        delete[] m_pTitleAsUTF8;

-        m_pTitleAsUTF8 = NULL;

-    }

-}

-

-long long SegmentInfo::GetTimeCodeScale() const

-{

-    return m_timecodeScale;

-}

-

-

-long long SegmentInfo::GetDuration() const

-{

-    if (m_duration < 0)

-        return -1;

-

-    assert(m_timecodeScale >= 1);

-

-    const double dd = double(m_duration) * double(m_timecodeScale);

-    const long long d = static_cast<long long>(dd);

-

-    return d;

-}

-

-const char* SegmentInfo::GetMuxingAppAsUTF8() const

-{

-    return m_pMuxingAppAsUTF8;

-}

-

-

-const char* SegmentInfo::GetWritingAppAsUTF8() const

-{

-    return m_pWritingAppAsUTF8;

-}

-

-const char* SegmentInfo::GetTitleAsUTF8() const

-{

-    return m_pTitleAsUTF8;

-}

-

-Track::Track(Segment* pSegment, const Info& i) :

-    m_pSegment(pSegment),

-    m_info(i)

-{

-}

-

-Track::~Track()

-{

-    Info& info = const_cast<Info&>(m_info);

-    info.Clear();

-}

-

-Track::Info::Info():

-    type(-1),

-    number(-1),

-    uid(-1),

-    nameAsUTF8(NULL),

-    codecId(NULL),

-    codecPrivate(NULL),

-    codecPrivateSize(0),

-    codecNameAsUTF8(NULL)

-{

-}

-

-

-void Track::Info::Clear()

-{

-    delete[] nameAsUTF8;

-    nameAsUTF8 = NULL;

-

-    delete[] codecId;

-    codecId = NULL;

-

-    delete[] codecPrivate;

-    codecPrivate = NULL;

-

-    codecPrivateSize = 0;

-

-    delete[] codecNameAsUTF8;

-    codecNameAsUTF8 = NULL;

-}

-

-const BlockEntry* Track::GetEOS() const

-{

-    return &m_eos;

-}

-

-long long Track::GetType() const

-{

-    return m_info.type;

-}

-

-long long Track::GetNumber() const

-{

-    return m_info.number;

-}

-

-const char* Track::GetNameAsUTF8() const

-{

-    return m_info.nameAsUTF8;

-}

-

-const char* Track::GetCodecNameAsUTF8() const

-{

-    return m_info.codecNameAsUTF8;

-}

-

-

-const char* Track::GetCodecId() const

-{

-    return m_info.codecId;

-}

-

-const unsigned char* Track::GetCodecPrivate(size_t& size) const

-{

-    size = m_info.codecPrivateSize;

-    return m_info.codecPrivate;

-}

-

-

-long Track::GetFirst(const BlockEntry*& pBlockEntry) const

-{

-    Cluster* pCluster = m_pSegment->GetFirst();

-

-    //If Segment::GetFirst returns NULL, then this must be a network

-    //download, and we haven't loaded any clusters yet.  In this case,

-    //returning NULL from Track::GetFirst means the same thing.

-

-    for (int i = 0; i < 100; ++i)  //arbitrary upper bound

-    {

-        if (pCluster == NULL)

-        {

-            pBlockEntry = GetEOS();

-            return 1;

-        }

-

-        if (pCluster->EOS())

-        {

-            if (m_pSegment->Unparsed() <= 0)  //all clusters have been loaded

-            {

-                pBlockEntry = GetEOS();

-                return 1;

-            }

-

-            pBlockEntry = 0;

-            return E_BUFFER_NOT_FULL;

-        }

-

-        pBlockEntry = pCluster->GetFirst();

-

-        while (pBlockEntry)

-        {

-            const Block* const pBlock = pBlockEntry->GetBlock();

-            assert(pBlock);

-

-            if (pBlock->GetTrackNumber() == m_info.number)

-                return 0;

-

-            pBlockEntry = pCluster->GetNext(pBlockEntry);

-        }

-

-        pCluster = m_pSegment->GetNext(pCluster);

-    }

-

-    //NOTE: if we get here, it means that we didn't find a block with

-    //a matching track number.  We interpret that as an error (which

-    //might be too conservative).

-

-    pBlockEntry = GetEOS();  //so we can return a non-NULL value

-    return 1;

-}

-

-

-long Track::GetNext(

-    const BlockEntry* pCurrEntry,

-    const BlockEntry*& pNextEntry) const

-{

-    assert(pCurrEntry);

-    assert(!pCurrEntry->EOS());  //?

-

-    const Block* const pCurrBlock = pCurrEntry->GetBlock();

-    assert(pCurrBlock->GetTrackNumber() == m_info.number);

-

-    Cluster* pCluster = pCurrEntry->GetCluster();

-    assert(pCluster);

-    assert(!pCluster->EOS());

-

-    pNextEntry = pCluster->GetNext(pCurrEntry);

-

-    for (int i = 0; i < 100; ++i)  //arbitrary upper bound to search

-    {

-        while (pNextEntry)

-        {

-            const Block* const pNextBlock = pNextEntry->GetBlock();

-            assert(pNextBlock);

-

-            if (pNextBlock->GetTrackNumber() == m_info.number)

-                return 0;

-

-            pNextEntry = pCluster->GetNext(pNextEntry);

-        }

-

-        pCluster = m_pSegment->GetNext(pCluster);

-

-        if (pCluster == NULL)

-        {

-            pNextEntry = GetEOS();

-            return 1;

-        }

-

-        if (pCluster->EOS())

-        {

-            if (m_pSegment->Unparsed() <= 0)   //all clusters have been loaded

-            {

-                pNextEntry = GetEOS();

-                return 1;

-            }

-

-            //TODO: there is a potential O(n^2) problem here: we tell the

-            //caller to (pre)load another cluster, which he does, but then he

-            //calls GetNext again, which repeats the same search.  This is

-            //a pathological case, since the only way it can happen is if

-            //there exists a long sequence of clusters none of which contain a

-            // block from this track.  One way around this problem is for the

-            //caller to be smarter when he loads another cluster: don't call

-            //us back until you have a cluster that contains a block from this

-            //track. (Of course, that's not cheap either, since our caller

-            //would have to scan the each cluster as it's loaded, so that

-            //would just push back the problem.)

-

-            pNextEntry = NULL;

-            return E_BUFFER_NOT_FULL;

-        }

-

-        pNextEntry = pCluster->GetFirst();

-    }

-

-    //NOTE: if we get here, it means that we didn't find a block with

-    //a matching track number after lots of searching, so we give

-    //up trying.

-

-    pNextEntry = GetEOS();  //so we can return a non-NULL value

-    return 1;

-}

-

-

-Track::EOSBlock::EOSBlock()

-{

-}

-

-

-bool Track::EOSBlock::EOS() const

-{

-    return true;

-}

-

-

-Cluster* Track::EOSBlock::GetCluster() const

-{

-    return NULL;

-}

-

-

-size_t Track::EOSBlock::GetIndex() const

-{

-    return 0;

-}

-

-

-const Block* Track::EOSBlock::GetBlock() const

-{

-    return NULL;

-}

-

-

-bool Track::EOSBlock::IsBFrame() const

-{

-    return false;

-}

-

-

-VideoTrack::VideoTrack(Segment* pSegment, const Info& i) :

-    Track(pSegment, i),

-    m_width(-1),

-    m_height(-1),

-    m_rate(-1)

-{

-    assert(i.type == 1);

-    assert(i.number > 0);

-

-    IMkvReader* const pReader = pSegment->m_pReader;

-

-    const Settings& s = i.settings;

-    assert(s.start >= 0);

-    assert(s.size >= 0);

-

-    long long pos = s.start;

-    assert(pos >= 0);

-

-    const long long stop = pos + s.size;

-

-    while (pos < stop)

-    {

-#ifdef _DEBUG

-        long len;

-        const long long id = ReadUInt(pReader, pos, len);

-        assert(id >= 0);  //TODO: handle error case

-        assert((pos + len) <= stop);

-#endif

-        if (Match(pReader, pos, 0x30, m_width))

-            ;

-        else if (Match(pReader, pos, 0x3A, m_height))

-            ;

-        else if (Match(pReader, pos, 0x0383E3, m_rate))

-            ;

-        else

-        {

-            long len;

-            const long long id = ReadUInt(pReader, pos, len);

-            assert(id >= 0);  //TODO: handle error case

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume id

-

-            const long long size = ReadUInt(pReader, pos, len);

-            assert(size >= 0);  //TODO: handle error case

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume length of size

-            assert((pos + size) <= stop);

-

-            //pos now designates start of payload

-

-            pos += size;  //consume payload

-            assert(pos <= stop);

-        }

-    }

-

-    return;

-}

-

-

-bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const

-{

-    assert(pBlockEntry);

-

-    const Block* const pBlock = pBlockEntry->GetBlock();

-    assert(pBlock);

-    assert(pBlock->GetTrackNumber() == m_info.number);

-

-    return pBlock->IsKey();

-}

-

-

-long long VideoTrack::GetWidth() const

-{

-    return m_width;

-}

-

-

-long long VideoTrack::GetHeight() const

-{

-    return m_height;

-}

-

-

-double VideoTrack::GetFrameRate() const

-{

-    return m_rate;

-}

-

-

-AudioTrack::AudioTrack(Segment* pSegment, const Info& i) :

-    Track(pSegment, i),

-    m_rate(0.0),

-    m_channels(0),

-    m_bitDepth(-1)

-{

-    assert(i.type == 2);

-    assert(i.number > 0);

-

-    IMkvReader* const pReader = pSegment->m_pReader;

-

-    const Settings& s = i.settings;

-    assert(s.start >= 0);

-    assert(s.size >= 0);

-

-    long long pos = s.start;

-    assert(pos >= 0);

-

-    const long long stop = pos + s.size;

-

-    while (pos < stop)

-    {

-#ifdef _DEBUG

-        long len;

-        const long long id = ReadUInt(pReader, pos, len);

-        assert(id >= 0);  //TODO: handle error case

-        assert((pos + len) <= stop);

-#endif

-        if (Match(pReader, pos, 0x35, m_rate))

-            ;

-        else if (Match(pReader, pos, 0x1F, m_channels))

-            ;

-        else if (Match(pReader, pos, 0x2264, m_bitDepth))

-            ;

-        else

-        {

-            long len;

-            const long long id = ReadUInt(pReader, pos, len);

-            assert(id >= 0);  //TODO: handle error case

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume id

-

-            const long long size = ReadUInt(pReader, pos, len);

-            assert(size >= 0);  //TODO: handle error case

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume length of size

-            assert((pos + size) <= stop);

-

-            //pos now designates start of payload

-

-            pos += size;  //consume payload

-            assert(pos <= stop);

-        }

-    }

-

-    return;

-}

-

-

-bool AudioTrack::VetEntry(const BlockEntry* pBlockEntry) const

-{

-    assert(pBlockEntry);

-

-    const Block* const pBlock = pBlockEntry->GetBlock();

-    assert(pBlock);

-    assert(pBlock->GetTrackNumber() == m_info.number);

-

-    return true;

-}

-

-

-double AudioTrack::GetSamplingRate() const

-{

-    return m_rate;

-}

-

-

-long long AudioTrack::GetChannels() const

-{

-    return m_channels;

-}

-

-long long AudioTrack::GetBitDepth() const

-{

-    return m_bitDepth;

-}

-

-Tracks::Tracks(Segment* pSegment, long long start, long long size_) :

-    m_pSegment(pSegment),

-    m_start(start),

-    m_size(size_),

-    m_trackEntries(NULL),

-    m_trackEntriesEnd(NULL)

-{

-    long long stop = m_start + m_size;

-    IMkvReader* const pReader = m_pSegment->m_pReader;

-

-    long long pos1 = m_start;

-    int count = 0;

-

-    while (pos1 < stop)

-    {

-        long len;

-        const long long id = ReadUInt(pReader, pos1, len);

-        assert(id >= 0);

-        assert((pos1 + len) <= stop);

-

-        pos1 += len;  //consume id

-

-        const long long size = ReadUInt(pReader, pos1, len);

-        assert(size >= 0);

-        assert((pos1 + len) <= stop);

-

-        pos1 += len;  //consume length of size

-

-        //pos now desinates start of element

-        if (id == 0x2E)  //TrackEntry ID

-            ++count;

-

-        pos1 += size;  //consume payload

-        assert(pos1 <= stop);

-    }

-

-    if (count <= 0)

-        return;

-

-    m_trackEntries = new Track*[count];

-    m_trackEntriesEnd = m_trackEntries;

-

-    long long pos = m_start;

-

-    while (pos < stop)

-    {

-        long len;

-        const long long id = ReadUInt(pReader, pos, len);

-        assert(id >= 0);

-        assert((pos + len) <= stop);

-

-        pos += len;  //consume id

-

-        const long long size1 = ReadUInt(pReader, pos, len);

-        assert(size1 >= 0);

-        assert((pos + len) <= stop);

-

-        pos += len;  //consume length of size

-

-        //pos now desinates start of element

-

-        if (id == 0x2E)  //TrackEntry ID

-            ParseTrackEntry(pos, size1, *m_trackEntriesEnd++);

-

-        pos += size1;  //consume payload

-        assert(pos <= stop);

-    }

-}

-

-

-unsigned long Tracks::GetTracksCount() const

-{

-    const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries;

-    assert(result >= 0);

-

-    return static_cast<unsigned long>(result);

-}

-

-

-void Tracks::ParseTrackEntry(

-    long long start,

-    long long size,

-    Track*& pTrack)

-{

-    IMkvReader* const pReader = m_pSegment->m_pReader;

-

-    long long pos = start;

-    const long long stop = start + size;

-

-    Track::Info i;

-

-    Track::Settings videoSettings;

-    videoSettings.start = -1;

-

-    Track::Settings audioSettings;

-    audioSettings.start = -1;

-

-    while (pos < stop)

-    {

-#ifdef _DEBUG

-        long len;

-        const long long id = ReadUInt(pReader, pos, len);

-        len;

-        id;

-#endif

-        if (Match(pReader, pos, 0x57, i.number))

-            assert(i.number > 0);

-        else if (Match(pReader, pos, 0x33C5, i.uid))

-            ;

-        else if (Match(pReader, pos, 0x03, i.type))

-            ;

-        else if (Match(pReader, pos, 0x136E, i.nameAsUTF8))

-            assert(i.nameAsUTF8);

-        else if (Match(pReader, pos, 0x06, i.codecId))

-            ;

-        else if (Match(pReader,

-                       pos,

-                       0x23A2,

-                       i.codecPrivate,

-                       i.codecPrivateSize))

-            ;

-        else if (Match(pReader, pos, 0x058688, i.codecNameAsUTF8))

-            assert(i.codecNameAsUTF8);

-        else

-        {

-            long len;

-

-            const long long id = ReadUInt(pReader, pos, len);

-            assert(id >= 0);  //TODO: handle error case

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume id

-

-            const long long size = ReadUInt(pReader, pos, len);

-            assert(size >= 0);  //TODO: handle error case

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume length of size

-            const long long start = pos;

-

-            pos += size;  //consume payload

-            assert(pos <= stop);

-

-            if (id == 0x60)

-            {

-                videoSettings.start = start;

-                videoSettings.size = size;

-            }

-            else if (id == 0x61)

-            {

-                audioSettings.start = start;

-                audioSettings.size = size;

-            }

-        }

-    }

-

-    assert(pos == stop);

-    //TODO: propertly vet info.number, to ensure both its existence,

-    //and that it is unique among all tracks.

-    assert(i.number > 0);

-

-    //TODO: vet settings, to ensure that video settings (0x60)

-    //were specified when type = 1, and that audio settings (0x61)

-    //were specified when type = 2.

-    if (i.type == 1)  //video

-    {

-        assert(audioSettings.start < 0);

-        assert(videoSettings.start >= 0);

-

-        i.settings = videoSettings;

-

-        VideoTrack* const t = new VideoTrack(m_pSegment, i);

-        assert(t);  //TODO

-        pTrack = t;

-    }

-    else if (i.type == 2)  //audio

-    {

-        assert(videoSettings.start < 0);

-        assert(audioSettings.start >= 0);

-

-        i.settings = audioSettings;

-

-        AudioTrack* const t = new  AudioTrack(m_pSegment, i);

-        assert(t);  //TODO

-        pTrack = t;

-    }

-    else

-    {

-        // for now we do not support other track types yet.

-        // TODO: support other track types

-        i.Clear();

-

-        pTrack = NULL;

-    }

-

-    return;

-}

-

-

-Tracks::~Tracks()

-{

-    Track** i = m_trackEntries;

-    Track** const j = m_trackEntriesEnd;

-

-    while (i != j)

-    {

-        Track* const pTrack = *i++;

-        delete pTrack;

-    }

-

-    delete[] m_trackEntries;

-}

-

-

-Track* Tracks::GetTrackByNumber(unsigned long tn_) const

-{

-    const long long tn = tn_;

-

-    Track** i = m_trackEntries;

-    Track** const j = m_trackEntriesEnd;

-

-    while (i != j)

-    {

-        Track* const pTrack = *i++;

-

-        if (pTrack == NULL)

-            continue;

-

-        if (tn == pTrack->GetNumber())

-            return pTrack;

-    }

-

-    return NULL;  //not found

-}

-

-

-Track* Tracks::GetTrackByIndex(unsigned long idx) const

-{

-    const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries;

-

-    if (idx >= static_cast<unsigned long>(count))

-         return NULL;

-

-    return m_trackEntries[idx];

-}

-

-

-void Cluster::Load()

-{

-    assert(m_pSegment);

-    assert(m_pos);

-    assert(m_size);

-

-    if (m_pos > 0)  //loaded

-    {

-        assert(m_size > 0);

-        assert(m_timecode >= 0);

-        return;

-    }

-

-    assert(m_pos < 0);  //not loaded yet

-    assert(m_size < 0);

-    assert(m_timecode < 0);

-

-    IMkvReader* const pReader = m_pSegment->m_pReader;

-

-    m_pos *= -1;                                  //relative to segment

-    long long pos = m_pSegment->m_start + m_pos;  //absolute

-

-    long len;

-

-    const long long id_ = ReadUInt(pReader, pos, len);

-    assert(id_ >= 0);

-    assert(id_ == 0x0F43B675);  //Cluster ID

-

-    pos += len;  //consume id

-

-    const long long size_ = ReadUInt(pReader, pos, len);

-    assert(size_ >= 0);

-

-    pos += len;  //consume size

-

-    m_size = size_;

-    const long long stop = pos + size_;

-

-    long long timecode = -1;

-

-    while (pos < stop)

-    {

-        if (Match(pReader, pos, 0x67, timecode))

-            break;

-        else

-        {

-            const long long id = ReadUInt(pReader, pos, len);

-            assert(id >= 0);  //TODO

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume id

-

-            const long long size = ReadUInt(pReader, pos, len);

-            assert(size >= 0);  //TODO

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume size

-

-            if (id == 0x20)  //BlockGroup ID

-                break;

-

-            if (id == 0x23)  //SimpleBlock ID

-                break;

-

-            pos += size;  //consume payload

-            assert(pos <= stop);

-        }

-    }

-

-    assert(pos <= stop);

-    assert(timecode >= 0);

-

-    m_timecode = timecode;

-}

-

-

-Cluster* Cluster::Parse(

-    Segment* pSegment,

-    long idx,

-    long long off)

-{

-    assert(pSegment);

-    assert(off >= 0);

-    assert(off < pSegment->m_size);

-

-    Cluster* const pCluster = new Cluster(pSegment, idx, -off);

-    assert(pCluster);

-

-    return pCluster;

-}

-

-

-Cluster::Cluster() :

-    m_pSegment(NULL),

-    m_index(0),

-    m_pos(0),

-    m_size(0),

-    m_timecode(0),

-    m_entries(NULL),

-    m_entriesCount(0)

-{

-}

-

-

-Cluster::Cluster(

-    Segment* pSegment,

-    long idx,

-    long long off) :

-    m_pSegment(pSegment),

-    m_index(idx),

-    m_pos(off),

-    m_size(-1),

-    m_timecode(-1),

-    m_entries(NULL),

-    m_entriesCount(0)

-{

-}

-

-

-Cluster::~Cluster()

-{

-    BlockEntry** i = m_entries;

-    BlockEntry** const j = m_entries + m_entriesCount;

-

-    while (i != j)

-    {

-         BlockEntry* p = *i++;

-         assert(p);

-

-         delete p;

-    }

-

-    delete[] m_entries;

-}

-

-

-bool Cluster::EOS() const

-{

-    return (m_pSegment == NULL);

-}

-

-

-void Cluster::LoadBlockEntries()

-{

-    if (m_entries)

-        return;

-

-    assert(m_pSegment);

-    assert(m_pos);

-    assert(m_size);

-    assert(m_entriesCount == 0);

-

-    IMkvReader* const pReader = m_pSegment->m_pReader;

-

-    if (m_pos < 0)

-        m_pos *= -1;  //relative to segment

-

-    long long pos = m_pSegment->m_start + m_pos;  //absolute

-

-    {

-        long len;

-

-        const long long id = ReadUInt(pReader, pos, len);

-        id;

-        assert(id >= 0);

-        assert(id == 0x0F43B675);  //Cluster ID

-

-        pos += len;  //consume id

-

-        const long long size = ReadUInt(pReader, pos, len);

-        assert(size > 0);

-

-        pos += len;  //consume size

-

-        //pos now points to start of payload

-

-        if (m_size >= 0)

-            assert(size == m_size);

-        else

-            m_size = size;

-    }

-

-    const long long stop = pos + m_size;

-    long long timecode = -1;  //of cluster itself

-

-    //First count the number of entries

-

-    long long idx = pos;  //points to start of payload

-    m_entriesCount = 0;

-

-    while (idx < stop)

-    {

-        if (Match(pReader, idx, 0x67, timecode))

-        {

-            if (m_timecode >= 0)

-                assert(timecode == m_timecode);

-            else

-                m_timecode = timecode;

-        }

-        else

-        {

-            long len;

-

-            const long long id = ReadUInt(pReader, idx, len);

-            assert(id >= 0);  //TODO

-            assert((idx + len) <= stop);

-

-            idx += len;  //consume id

-

-            const long long size = ReadUInt(pReader, idx, len);

-            assert(size >= 0);  //TODO

-            assert((idx + len) <= stop);

-

-            idx += len;  //consume size

-

-            if (id == 0x20)  //BlockGroup ID

-                ++m_entriesCount;

-            else if (id == 0x23)  //SimpleBlock ID

-                ++m_entriesCount;

-

-            idx += size;  //consume payload

-            assert(idx <= stop);

-        }

-    }

-

-    assert(idx == stop);

-    assert(m_timecode >= 0);

-

-    if (m_entriesCount == 0)  //TODO: handle empty clusters

-        return;

-

-    m_entries = new BlockEntry*[m_entriesCount];

-    size_t index = 0;

-

-    while (pos < stop)

-    {

-        if (Match(pReader, pos, 0x67, timecode))

-            assert(timecode == m_timecode);

-        else

-        {

-            long len;

-            const long long id = ReadUInt(pReader, pos, len);

-            assert(id >= 0);  //TODO

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume id

-

-            const long long size = ReadUInt(pReader, pos, len);

-            assert(size >= 0);  //TODO

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume size

-

-            if (id == 0x20)  //BlockGroup ID

-                ParseBlockGroup(pos, size, index++);

-            else if (id == 0x23)  //SimpleBlock ID

-                ParseSimpleBlock(pos, size, index++);

-

-            pos += size;  //consume payload

-            assert(pos <= stop);

-        }

-    }

-

-    assert(pos == stop);

-    assert(timecode >= 0);

-    assert(index == m_entriesCount);

-}

-

-

-

-long long Cluster::GetTimeCode()

-{

-    Load();

-    return m_timecode;

-}

-

-

-long long Cluster::GetTime()

-{

-    const long long tc = GetTimeCode();

-    assert(tc >= 0);

-

-    const SegmentInfo* const pInfo = m_pSegment->GetInfo();

-    assert(pInfo);

-

-    const long long scale = pInfo->GetTimeCodeScale();

-    assert(scale >= 1);

-

-    const long long t = m_timecode * scale;

-

-    return t;

-}

-

-

-long long Cluster::GetFirstTime()

-{

-    const BlockEntry* const pEntry = GetFirst();

-

-    if (pEntry == NULL)  //empty cluster

-        return GetTime();

-

-    const Block* const pBlock = pEntry->GetBlock();

-    assert(pBlock);

-

-    return pBlock->GetTime(this);

-}

-

-

-long long Cluster::GetLastTime()

-{

-    const BlockEntry* const pEntry = GetLast();

-

-    if (pEntry == NULL)  //empty cluster

-        return GetTime();

-

-    const Block* const pBlock = pEntry->GetBlock();

-    assert(pBlock);

-

-    return pBlock->GetTime(this);

-}

-

-

-void Cluster::ParseBlockGroup(long long start, long long size, size_t index)

-{

-    assert(m_entries);

-    assert(m_entriesCount);

-    assert(index < m_entriesCount);

-

-    BlockGroup* const pGroup =

-        new (std::nothrow) BlockGroup(this, index, start, size);

-    assert(pGroup);  //TODO

-

-    m_entries[index] = pGroup;

-}

-

-

-

-void Cluster::ParseSimpleBlock(long long start, long long size, size_t index)

-{

-    assert(m_entries);

-    assert(m_entriesCount);

-    assert(index < m_entriesCount);

-

-    SimpleBlock* const pSimpleBlock =

-        new (std::nothrow) SimpleBlock(this, index, start, size);

-    assert(pSimpleBlock);  //TODO

-

-    m_entries[index] = pSimpleBlock;

-}

-

-

-const BlockEntry* Cluster::GetFirst()

-{

-    LoadBlockEntries();

-    //assert(m_entries);

-    //assert(m_entriesCount >= 1);

-

-    if ((m_entries == NULL) || (m_entriesCount == 0))

-        return NULL;

-

-    const BlockEntry* const pFirst = m_entries[0];

-    assert(pFirst);

-

-    return pFirst;

-}

-

-

-const BlockEntry* Cluster::GetLast()

-{

-    LoadBlockEntries();

-    //assert(m_entries);

-    //assert(m_entriesCount >= 1);

-

-    if ((m_entries == NULL) || (m_entriesCount == 0))

-        return NULL;

-

-    const size_t idx = m_entriesCount - 1;

-

-    const BlockEntry* const pLast = m_entries[idx];

-    assert(pLast);

-

-    return pLast;

-}

-

-

-const BlockEntry* Cluster::GetNext(const BlockEntry* pEntry) const

-{

-    assert(pEntry);

-    assert(m_entries);

-    assert(m_entriesCount);

-

-    size_t idx = pEntry->GetIndex();

-    assert(idx < m_entriesCount);

-    assert(m_entries[idx] == pEntry);

-

-    ++idx;

-

-    if (idx >= m_entriesCount)

-      return NULL;

-

-    return m_entries[idx];

-}

-

-

-const BlockEntry* Cluster::GetEntry(const Track* pTrack)

-{

-    assert(pTrack);

-

-    if (m_pSegment == NULL)  //EOS

-        return pTrack->GetEOS();

-

-    LoadBlockEntries();

-

-    if ((m_entries == NULL) || (m_entriesCount == 0))

-        return NULL;

-

-    BlockEntry** i = m_entries;

-    assert(i);

-

-    BlockEntry** const j = i + m_entriesCount;

-

-    while (i != j)

-    {

-        const BlockEntry* const pEntry = *i++;

-        assert(pEntry);

-        assert(!pEntry->EOS());

-

-        const Block* const pBlock = pEntry->GetBlock();

-        assert(pBlock);

-

-        if (pBlock->GetTrackNumber() != pTrack->GetNumber())

-            continue;

-

-        if (pTrack->VetEntry(pEntry))

-            return pEntry;

-    }

-

-    return pTrack->GetEOS();  //no satisfactory block found

-}

-

-

-const BlockEntry*

-Cluster::GetEntry(

-    const CuePoint& cp,

-    const CuePoint::TrackPosition& tp)

-{

-    assert(m_pSegment);

-

-    LoadBlockEntries();

-

-    if (m_entries == NULL)

-        return NULL;

-

-    const long long count = m_entriesCount;

-

-    if (count <= 0)

-        return NULL;

-

-    const long long tc = cp.GetTimeCode();

-

-    if ((tp.m_block > 0) && (tp.m_block <= count))

-    {

-        const size_t block = static_cast<size_t>(tp.m_block);

-        const size_t index = block - 1;

-

-        const BlockEntry* const pEntry = m_entries[index];

-        assert(pEntry);

-        assert(!pEntry->EOS());

-

-        const Block* const pBlock = pEntry->GetBlock();

-        assert(pBlock);

-

-        if ((pBlock->GetTrackNumber() == tp.m_track) &&

-            (pBlock->GetTimeCode(this) == tc))

-        {

-            return pEntry;

-        }

-    }

-

-    const BlockEntry* const* i = m_entries;

-    const BlockEntry* const* const j = i + count;

-

-    while (i != j)

-    {

-        const BlockEntry* const pEntry = *i++;

-        assert(pEntry);

-        assert(!pEntry->EOS());

-

-        const Block* const pBlock = pEntry->GetBlock();

-        assert(pBlock);

-

-        if (pBlock->GetTrackNumber() != tp.m_track)

-            continue;

-

-        const long long tc_ = pBlock->GetTimeCode(this);

-

-        if (tc_ < tc)

-            continue;

-

-        if (tc_ > tc)

-            return NULL;

-

-        const Tracks* const pTracks = m_pSegment->GetTracks();

-        assert(pTracks);

-

-        const long tn = static_cast<long>(tp.m_track);

-        const Track* const pTrack = pTracks->GetTrackByNumber(tn);

-

-        if (pTrack == NULL)

-            return NULL;

-

-        const long long type = pTrack->GetType();

-

-        if (type == 2)  //audio

-            return pEntry;

-

-        if (type != 1)  //not video

-            return NULL;

-

-        if (!pBlock->IsKey())

-            return NULL;

-

-        return pEntry;

-    }

-

-    return NULL;

-}

-

-

-const BlockEntry* Cluster::GetMaxKey(const VideoTrack* pTrack)

-{

-    assert(pTrack);

-

-    if (m_pSegment == NULL)  //EOS

-        return pTrack->GetEOS();

-

-    LoadBlockEntries();

-    //assert(m_entries);

-

-    BlockEntry** i = m_entries + m_entriesCount;

-    BlockEntry** const j = m_entries;

-

-    while (i != j)

-    {

-        const BlockEntry* const pEntry = *--i;

-        assert(pEntry);

-        assert(!pEntry->EOS());

-

-        const Block* const pBlock = pEntry->GetBlock();

-        assert(pBlock);

-

-        if (pBlock->GetTrackNumber() != pTrack->GetNumber())

-            continue;

-

-        if (pBlock->IsKey())

-            return pEntry;

-    }

-

-    return pTrack->GetEOS();  //no satisfactory block found

-}

-

-

-

-BlockEntry::BlockEntry()

-{

-}

-

-

-BlockEntry::~BlockEntry()

-{

-}

-

-

-SimpleBlock::SimpleBlock(

-    Cluster* pCluster,

-    size_t idx,

-    long long start,

-    long long size) :

-    m_pCluster(pCluster),

-    m_index(idx),

-    m_block(start, size, pCluster->m_pSegment->m_pReader)

-{

-}

-

-

-bool SimpleBlock::EOS() const

-{

-    return false;

-}

-

-

-Cluster* SimpleBlock::GetCluster() const

-{

-    return m_pCluster;

-}

-

-

-size_t SimpleBlock::GetIndex() const

-{

-    return m_index;

-}

-

-

-const Block* SimpleBlock::GetBlock() const

-{

-    return &m_block;

-}

-

-

-bool SimpleBlock::IsBFrame() const

-{

-    return false;

-}

-

-

-BlockGroup::BlockGroup(

-    Cluster* pCluster,

-    size_t idx,

-    long long start,

-    long long size_) :

-    m_pCluster(pCluster),

-    m_index(idx),

-    m_prevTimeCode(0),

-    m_nextTimeCode(0),

-    m_pBlock(NULL)  //TODO: accept multiple blocks within a block group

-{

-    IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader;

-

-    long long pos = start;

-    const long long stop = start + size_;

-

-    bool bSimpleBlock = false;

-    bool bReferenceBlock = false;

-

-    while (pos < stop)

-    {

-        short t;

-

-        if (Match(pReader, pos, 0x7B, t))

-        {

-            if (t < 0)

-                m_prevTimeCode = t;

-            else if (t > 0)

-                m_nextTimeCode = t;

-            else

-                assert(false);

-

-            bReferenceBlock = true;

-        }

-        else

-        {

-            long len;

-            const long long id = ReadUInt(pReader, pos, len);

-            assert(id >= 0);  //TODO

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume ID

-

-            const long long size = ReadUInt(pReader, pos, len);

-            assert(size >= 0);  //TODO

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume size

-

-            switch (id)

-            {

-                case 0x23:  //SimpleBlock ID

-                    bSimpleBlock = true;

-                    //YES, FALL THROUGH TO NEXT CASE

-

-                case 0x21:  //Block ID

-                    ParseBlock(pos, size);

-                    break;

-

-                default:

-                    break;

-            }

-

-            pos += size;  //consume payload

-            assert(pos <= stop);

-        }

-    }

-

-    assert(pos == stop);

-    assert(m_pBlock);

-

-    if (!bSimpleBlock)

-        m_pBlock->SetKey(!bReferenceBlock);

-}

-

-

-BlockGroup::~BlockGroup()

-{

-    delete m_pBlock;

-}

-

-

-void BlockGroup::ParseBlock(long long start, long long size)

-{

-    IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader;

-

-    Block* const pBlock = new Block(start, size, pReader);

-    assert(pBlock);  //TODO

-

-    //TODO: the Matroska spec says you have multiple blocks within the

-    //same block group, with blocks ranked by priority (the flag bits).

-

-    assert(m_pBlock == NULL);

-    m_pBlock = pBlock;

-}

-

-

-bool BlockGroup::EOS() const

-{

-    return false;

-}

-

-

-Cluster* BlockGroup::GetCluster() const

-{

-    return m_pCluster;

-}

-

-

-size_t BlockGroup::GetIndex() const

-{

-    return m_index;

-}

-

-

-const Block* BlockGroup::GetBlock() const

-{

-    return m_pBlock;

-}

-

-

-short BlockGroup::GetPrevTimeCode() const

-{

-    return m_prevTimeCode;

-}

-

-

-short BlockGroup::GetNextTimeCode() const

-{

-    return m_nextTimeCode;

-}

-

-

-bool BlockGroup::IsBFrame() const

-{

-    return (m_nextTimeCode > 0);

-}

-

-

-

-Block::Block(long long start, long long size_, IMkvReader* pReader) :

-    m_start(start),

-    m_size(size_)

-{

-    long long pos = start;

-    const long long stop = start + size_;

-

-    long len;

-

-    m_track = ReadUInt(pReader, pos, len);

-    assert(m_track > 0);

-    assert((pos + len) <= stop);

-

-    pos += len;  //consume track number

-    assert((stop - pos) >= 2);

-

-    m_timecode = Unserialize2SInt(pReader, pos);

-

-    pos += 2;

-    assert((stop - pos) >= 1);

-

-    const long hr = pReader->Read(pos, 1, &m_flags);

-    assert(hr == 0L);

-

-    ++pos;

-    assert(pos <= stop);

-

-    m_frameOff = pos;

-

-    const long long frame_size = stop - pos;

-

-    assert(frame_size <= 2147483647L);

-

-    m_frameSize = static_cast<long>(frame_size);

-}

-

-

-long long Block::GetTimeCode(Cluster* pCluster) const

-{

-    assert(pCluster);

-

-    const long long tc0 = pCluster->GetTimeCode();

-    assert(tc0 >= 0);

-

-    const long long tc = tc0 + static_cast<long long>(m_timecode);

-    assert(tc >= 0);

-

-    return tc;  //unscaled timecode units

-}

-

-

-long long Block::GetTime(Cluster* pCluster) const

-{

-    assert(pCluster);

-

-    const long long tc = GetTimeCode(pCluster);

-

-    const Segment* const pSegment = pCluster->m_pSegment;

-    const SegmentInfo* const pInfo = pSegment->GetInfo();

-    assert(pInfo);

-

-    const long long scale = pInfo->GetTimeCodeScale();

-    assert(scale >= 1);

-

-    const long long ns = tc * scale;

-

-    return ns;

-}

-

-

-long long Block::GetTrackNumber() const

-{

-    return m_track;

-}

-

-

-bool Block::IsKey() const

-{

-    return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);

-}

-

-unsigned char Block::Flags() const {

-    return m_flags;

-}

-

-void Block::SetKey(bool bKey)

-{

-    if (bKey)

-        m_flags |= static_cast<unsigned char>(1 << 7);

-    else

-        m_flags &= 0x7F;

-}

-

-

-long long Block::GetOffset() const

-{

-  return m_frameOff;

-}

-

-

-long Block::GetSize() const

-{

-    return m_frameSize;

-}

-

-

-long Block::Read(IMkvReader* pReader, unsigned char* buf) const

-{

-

-    assert(pReader);

-    assert(buf);

-

-    const long hr = pReader->Read(m_frameOff, m_frameSize, buf);

-

-    return hr;

-}

-

-

-}  //end namespace mkvparser

diff --git a/media/libstagefright/matroska/mkvparser.hpp b/media/libstagefright/matroska/mkvparser.hpp
deleted file mode 100644
index f7d8948..0000000
--- a/media/libstagefright/matroska/mkvparser.hpp
+++ /dev/null
@@ -1,556 +0,0 @@
-// Copyright (c) 2010 The WebM project authors. All Rights Reserved.

-//

-// Use of this source code is governed by a BSD-style license

-// that can be found in the LICENSE file in the root of the source

-// tree. An additional intellectual property rights grant can be found

-// in the file PATENTS.  All contributing project authors may

-// be found in the AUTHORS file in the root of the source tree.

-

-#ifndef MKVPARSER_HPP

-#define MKVPARSER_HPP

-

-#include <cstdlib>

-#include <cstdio>

-

-namespace mkvparser

-{

-

-const int E_FILE_FORMAT_INVALID = -2;

-const int E_BUFFER_NOT_FULL = -3;

-

-class IMkvReader

-{

-public:

-    virtual int Read(long long pos, long len, unsigned char* buf) = 0;

-    virtual int Length(long long* total, long long* available) = 0;

-protected:

-    virtual ~IMkvReader();

-};

-

-long long GetUIntLength(IMkvReader*, long long, long&);

-long long ReadUInt(IMkvReader*, long long, long&);

-long long SyncReadUInt(IMkvReader*, long long pos, long long stop, long&);

-long long UnserializeUInt(IMkvReader*, long long pos, long long size);

-float Unserialize4Float(IMkvReader*, long long);

-double Unserialize8Double(IMkvReader*, long long);

-short Unserialize2SInt(IMkvReader*, long long);

-signed char Unserialize1SInt(IMkvReader*, long long);

-bool Match(IMkvReader*, long long&, unsigned long, long long&);

-bool Match(IMkvReader*, long long&, unsigned long, char*&);

-bool Match(IMkvReader*, long long&, unsigned long,unsigned char*&, size_t&);

-bool Match(IMkvReader*, long long&, unsigned long, double&);

-bool Match(IMkvReader*, long long&, unsigned long, short&);

-

-void GetVersion(int& major, int& minor, int& build, int& revision);

-

-struct EBMLHeader

-{

-    EBMLHeader();

-    ~EBMLHeader();

-    long long m_version;

-    long long m_readVersion;

-    long long m_maxIdLength;

-    long long m_maxSizeLength;

-    char* m_docType;

-    long long m_docTypeVersion;

-    long long m_docTypeReadVersion;

-

-    long long Parse(IMkvReader*, long long&);

-};

-

-

-class Segment;

-class Track;

-class Cluster;

-

-class Block

-{

-    Block(const Block&);

-    Block& operator=(const Block&);

-

-public:

-    const long long m_start;

-    const long long m_size;

-

-    Block(long long start, long long size, IMkvReader*);

-

-    long long GetTrackNumber() const;

-    long long GetTimeCode(Cluster*) const;  //absolute, but not scaled

-    long long GetTime(Cluster*) const;      //absolute, and scaled (ns units)

-    bool IsKey() const;

-    void SetKey(bool);

-

-    unsigned char Flags() const;

-

-    long long GetOffset() const;

-    long GetSize() const;

-    long Read(IMkvReader*, unsigned char*) const;

-

-private:

-    long long m_track;   //Track::Number()

-    short m_timecode;  //relative to cluster

-    unsigned char m_flags;

-    long long m_frameOff;

-    long m_frameSize;

-

-};

-

-

-class BlockEntry

-{

-    BlockEntry(const BlockEntry&);

-    BlockEntry& operator=(const BlockEntry&);

-

-public:

-    virtual ~BlockEntry();

-    virtual bool EOS() const = 0;

-    virtual Cluster* GetCluster() const = 0;

-    virtual size_t GetIndex() const = 0;

-    virtual const Block* GetBlock() const = 0;

-    virtual bool IsBFrame() const = 0;

-

-protected:

-    BlockEntry();

-

-};

-

-

-class SimpleBlock : public BlockEntry

-{

-    SimpleBlock(const SimpleBlock&);

-    SimpleBlock& operator=(const SimpleBlock&);

-

-public:

-    SimpleBlock(Cluster*, size_t, long long start, long long size);

-

-    bool EOS() const;

-    Cluster* GetCluster() const;

-    size_t GetIndex() const;

-    const Block* GetBlock() const;

-    bool IsBFrame() const;

-

-protected:

-    Cluster* const m_pCluster;

-    const size_t m_index;

-    Block m_block;

-

-};

-

-

-class BlockGroup : public BlockEntry

-{

-    BlockGroup(const BlockGroup&);

-    BlockGroup& operator=(const BlockGroup&);

-

-public:

-    BlockGroup(Cluster*, size_t, long long, long long);

-    ~BlockGroup();

-

-    bool EOS() const;

-    Cluster* GetCluster() const;

-    size_t GetIndex() const;

-    const Block* GetBlock() const;

-    bool IsBFrame() const;

-

-    short GetPrevTimeCode() const;  //relative to block's time

-    short GetNextTimeCode() const;  //as above

-

-protected:

-    Cluster* const m_pCluster;

-    const size_t m_index;

-

-private:

-    BlockGroup(Cluster*, size_t, unsigned long);

-    void ParseBlock(long long start, long long size);

-

-    short m_prevTimeCode;

-    short m_nextTimeCode;

-

-    //TODO: the Matroska spec says you can have multiple blocks within the

-    //same block group, with blocks ranked by priority (the flag bits).

-    //For now we just cache a single block.

-#if 0

-    typedef std::deque<Block*> blocks_t;

-    blocks_t m_blocks;  //In practice should contain only a single element.

-#else

-    Block* m_pBlock;

-#endif

-

-};

-

-

-class Track

-{

-    Track(const Track&);

-    Track& operator=(const Track&);

-

-public:

-    Segment* const m_pSegment;

-    virtual ~Track();

-

-    long long GetType() const;

-    long long GetNumber() const;

-    const char* GetNameAsUTF8() const;

-    const char* GetCodecNameAsUTF8() const;

-    const char* GetCodecId() const;

-    const unsigned char* GetCodecPrivate(size_t&) const;

-

-    const BlockEntry* GetEOS() const;

-

-    struct Settings

-    {

-        long long start;

-        long long size;

-    };

-

-    struct Info

-    {

-        long long type;

-        long long number;

-        long long uid;

-        char* nameAsUTF8;

-        char* codecId;

-        unsigned char* codecPrivate;

-        size_t codecPrivateSize;

-        char* codecNameAsUTF8;

-        Settings settings;

-        Info();

-        void Clear();

-    };

-

-    long GetFirst(const BlockEntry*&) const;

-    long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const;

-    virtual bool VetEntry(const BlockEntry*) const = 0;

-

-protected:

-    Track(Segment*, const Info&);

-    const Info m_info;

-

-    class EOSBlock : public BlockEntry

-    {

-    public:

-        EOSBlock();

-

-        bool EOS() const;

-        Cluster* GetCluster() const;

-        size_t GetIndex() const;

-        const Block* GetBlock() const;

-        bool IsBFrame() const;

-    };

-

-    EOSBlock m_eos;

-

-};

-

-

-class VideoTrack : public Track

-{

-    VideoTrack(const VideoTrack&);

-    VideoTrack& operator=(const VideoTrack&);

-

-public:

-    VideoTrack(Segment*, const Info&);

-    long long GetWidth() const;

-    long long GetHeight() const;

-    double GetFrameRate() const;

-

-    bool VetEntry(const BlockEntry*) const;

-

-private:

-    long long m_width;

-    long long m_height;

-    double m_rate;

-

-};

-

-

-class AudioTrack : public Track

-{

-    AudioTrack(const AudioTrack&);

-    AudioTrack& operator=(const AudioTrack&);

-

-public:

-    AudioTrack(Segment*, const Info&);

-    double GetSamplingRate() const;

-    long long GetChannels() const;

-    long long GetBitDepth() const;

-    bool VetEntry(const BlockEntry*) const;

-

-private:

-    double m_rate;

-    long long m_channels;

-    long long m_bitDepth;

-};

-

-

-class Tracks

-{

-    Tracks(const Tracks&);

-    Tracks& operator=(const Tracks&);

-

-public:

-    Segment* const m_pSegment;

-    const long long m_start;

-    const long long m_size;

-

-    Tracks(Segment*, long long start, long long size);

-    virtual ~Tracks();

-

-    Track* GetTrackByNumber(unsigned long tn) const;

-    Track* GetTrackByIndex(unsigned long idx) const;

-

-private:

-    Track** m_trackEntries;

-    Track** m_trackEntriesEnd;

-

-    void ParseTrackEntry(long long, long long, Track*&);

-

-public:

-    unsigned long GetTracksCount() const;

-};

-

-

-class SegmentInfo

-{

-    SegmentInfo(const SegmentInfo&);

-    SegmentInfo& operator=(const SegmentInfo&);

-

-public:

-    Segment* const m_pSegment;

-    const long long m_start;

-    const long long m_size;

-

-    SegmentInfo(Segment*, long long start, long long size);

-    ~SegmentInfo();

-    long long GetTimeCodeScale() const;

-    long long GetDuration() const;  //scaled

-    const char* GetMuxingAppAsUTF8() const;

-    const char* GetWritingAppAsUTF8() const;

-    const char* GetTitleAsUTF8() const;

-

-private:

-    long long m_timecodeScale;

-    double m_duration;

-    char* m_pMuxingAppAsUTF8;

-    char* m_pWritingAppAsUTF8;

-    char* m_pTitleAsUTF8;

-};

-

-class Cues;

-class CuePoint

-{

-    friend class Cues;

-

-    CuePoint(size_t, long long);

-    ~CuePoint();

-

-    CuePoint(const CuePoint&);

-    CuePoint& operator=(const CuePoint&);

-

-public:

-    void Load(IMkvReader*);

-

-    long long GetTimeCode() const;      //absolute but unscaled

-    long long GetTime(Segment*) const;  //absolute and scaled (ns units)

-

-    struct TrackPosition

-    {

-        long long m_track;

-        long long m_pos;  //of cluster

-        long long m_block;

-        //codec_state  //defaults to 0

-        //reference = clusters containing req'd referenced blocks

-        //  reftime = timecode of the referenced block

-

-        void Parse(IMkvReader*, long long, long long);

-    };

-

-    const TrackPosition* Find(const Track*) const;

-

-private:

-    const size_t m_index;

-    long long m_timecode;

-    TrackPosition* m_track_positions;

-    size_t m_track_positions_count;

-

-};

-

-

-class Cues

-{

-    friend class Segment;

-

-    Cues(Segment*, long long start, long long size);

-    ~Cues();

-

-    Cues(const Cues&);

-    Cues& operator=(const Cues&);

-

-public:

-    Segment* const m_pSegment;

-    const long long m_start;

-    const long long m_size;

-

-    bool Find(  //lower bound of time_ns

-        long long time_ns,

-        const Track*,

-        const CuePoint*&,

-        const CuePoint::TrackPosition*&) const;

-

-#if 0

-    bool FindNext(  //upper_bound of time_ns

-        long long time_ns,

-        const Track*,

-        const CuePoint*&,

-        const CuePoint::TrackPosition*&) const;

-#endif

-

-    const CuePoint* GetFirst() const;

-    const CuePoint* GetLast() const;

-

-    const CuePoint* GetNext(const CuePoint*) const;

-

-    const BlockEntry* GetBlock(

-                        const CuePoint*,

-                        const CuePoint::TrackPosition*) const;

-

-private:

-    void Init() const;

-    bool LoadCuePoint() const;

-    void PreloadCuePoint(size_t&, long long) const;

-

-    mutable CuePoint** m_cue_points;

-    mutable size_t m_count;

-    mutable size_t m_preload_count;

-    mutable long long m_pos;

-

-};

-

-

-class Cluster

-{

-    Cluster(const Cluster&);

-    Cluster& operator=(const Cluster&);

-

-public:

-    Segment* const m_pSegment;

-

-public:

-    static Cluster* Parse(Segment*, long, long long off);

-

-    Cluster();  //EndOfStream

-    ~Cluster();

-

-    bool EOS() const;

-

-    long long GetTimeCode();   //absolute, but not scaled

-    long long GetTime();       //absolute, and scaled (nanosecond units)

-    long long GetFirstTime();  //time (ns) of first (earliest) block

-    long long GetLastTime();   //time (ns) of last (latest) block

-

-    const BlockEntry* GetFirst();

-    const BlockEntry* GetLast();

-    const BlockEntry* GetNext(const BlockEntry*) const;

-    const BlockEntry* GetEntry(const Track*);

-    const BlockEntry* GetEntry(

-        const CuePoint&,

-        const CuePoint::TrackPosition&);

-    const BlockEntry* GetMaxKey(const VideoTrack*);

-

-protected:

-    Cluster(Segment*, long, long long off);

-

-public:

-    //TODO: these should all be private, with public selector functions

-    long m_index;

-    long long m_pos;

-    long long m_size;

-

-private:

-    long long m_timecode;

-    BlockEntry** m_entries;

-    size_t m_entriesCount;

-

-    void Load();

-    void LoadBlockEntries();

-    void ParseBlockGroup(long long, long long, size_t);

-    void ParseSimpleBlock(long long, long long, size_t);

-

-};

-

-

-class Segment

-{

-    friend class Cues;

-

-    Segment(const Segment&);

-    Segment& operator=(const Segment&);

-

-private:

-    Segment(IMkvReader*, long long pos, long long size);

-

-public:

-    IMkvReader* const m_pReader;

-    const long long m_start;  //posn of segment payload

-    const long long m_size;   //size of segment payload

-    Cluster m_eos;  //TODO: make private?

-

-    static long long CreateInstance(IMkvReader*, long long, Segment*&);

-    ~Segment();

-

-    long Load();  //loads headers and all clusters

-

-    //for incremental loading (splitter)

-    long long Unparsed() const;

-    long long ParseHeaders();  //stops when first cluster is found

-    long LoadCluster();        //loads one cluster

-

-#if 0

-    //This pair parses one cluster, but only changes the state of the

-    //segment object when the cluster is actually added to the index.

-    long ParseCluster(Cluster*&, long long& newpos) const;

-    bool AddCluster(Cluster*, long long);

-#endif

-

-    Tracks* GetTracks() const;

-    const SegmentInfo* GetInfo() const;

-    const Cues* GetCues() const;

-

-    long long GetDuration() const;

-

-    unsigned long GetCount() const;

-    Cluster* GetFirst();

-    Cluster* GetLast();

-    Cluster* GetNext(const Cluster*);

-

-    Cluster* FindCluster(long long time_nanoseconds);

-    const BlockEntry* Seek(long long time_nanoseconds, const Track*);

-

-private:

-

-    long long m_pos;  //absolute file posn; what has been consumed so far

-    SegmentInfo* m_pInfo;

-    Tracks* m_pTracks;

-    Cues* m_pCues;

-    Cluster** m_clusters;

-    long m_clusterCount;         //number of entries for which m_index >= 0

-    long m_clusterPreloadCount;  //number of entries for which m_index < 0

-    long m_clusterSize;          //array size

-

-    void AppendCluster(Cluster*);

-    void PreloadCluster(Cluster*, ptrdiff_t);

-

-    void ParseSeekHead(long long pos, long long size);

-    void ParseSeekEntry(long long pos, long long size);

-    void ParseCues(long long);

-

-    const BlockEntry* GetBlock(

-        const CuePoint&,

-        const CuePoint::TrackPosition&);

-

-};

-

-

-}  //end namespace mkvparser

-

-#endif  //MKVPARSER_HPP

diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index d081995..153cfe6 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -19,6 +19,7 @@
 #define ES_QUEUE_H_
 
 #include <media/stagefright/foundation/ABase.h>
+#include <utils/Errors.h>
 #include <utils/List.h>
 #include <utils/RefBase.h>
 
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
index 8bfe285..11d9c22 100644
--- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AMPEG4AudioAssembler"
+
 #include "AMPEG4AudioAssembler.h"
 
 #include "ARTPSource.h"
@@ -139,7 +142,10 @@
     return OK;
 }
 
-static status_t parseAudioSpecificConfig(ABitReader *bits) {
+static status_t parseAudioSpecificConfig(ABitReader *bits, sp<ABuffer> *asc) {
+    const uint8_t *dataStart = bits->data();
+    size_t totalNumBits = bits->numBitsLeft();
+
     unsigned audioObjectType;
     CHECK_EQ(parseAudioObjectType(bits, &audioObjectType), (status_t)OK);
 
@@ -185,13 +191,13 @@
         }
     }
 
-#if 0
-    // This is not supported here as the upper layers did not explicitly
-    // signal the length of AudioSpecificConfig.
-
     if (extensionAudioObjectType != 5 && bits->numBitsLeft() >= 16) {
+        size_t numBitsLeftAtStart = bits->numBitsLeft();
+
         unsigned syncExtensionType = bits->getBits(11);
         if (syncExtensionType == 0x2b7) {
+            LOGI("found syncExtension");
+
             CHECK_EQ(parseAudioObjectType(bits, &extensionAudioObjectType),
                      (status_t)OK);
 
@@ -203,9 +209,45 @@
                     /* unsigned extensionSamplingFrequency = */bits->getBits(24);
                 }
             }
+
+            size_t numBitsInExtension =
+                numBitsLeftAtStart - bits->numBitsLeft();
+
+            if (numBitsInExtension & 7) {
+                // Apparently an extension is always considered an even
+                // multiple of 8 bits long.
+
+                LOGI("Skipping %d bits after sync extension",
+                     8 - (numBitsInExtension & 7));
+
+                bits->skipBits(8 - (numBitsInExtension & 7));
+            }
+        } else {
+            bits->putBits(syncExtensionType, 11);
         }
     }
-#endif
+
+    if (asc != NULL) {
+        size_t bitpos = totalNumBits & 7;
+
+        ABitReader bs(dataStart, (totalNumBits + 7) / 8);
+
+        totalNumBits -= bits->numBitsLeft();
+
+        size_t numBytes = (totalNumBits + 7) / 8;
+
+        *asc = new ABuffer(numBytes);
+
+        if (bitpos & 7) {
+            bs.skipBits(8 - (bitpos & 7));
+        }
+
+        uint8_t *dstPtr = (*asc)->data();
+        while (numBytes > 0) {
+            *dstPtr++ = bs.getBits(8);
+            --numBytes;
+        }
+    }
 
     return OK;
 }
@@ -214,6 +256,7 @@
         ABitReader *bits,
         unsigned *numSubFrames,
         unsigned *frameLengthType,
+        ssize_t *fixedFrameLength,
         bool *otherDataPresent,
         unsigned *otherDataLenBits) {
     unsigned audioMuxVersion = bits->getBits(1);
@@ -242,12 +285,14 @@
 
     if (audioMuxVersion == 0) {
         // AudioSpecificConfig
-        CHECK_EQ(parseAudioSpecificConfig(bits), (status_t)OK);
+        CHECK_EQ(parseAudioSpecificConfig(bits, NULL /* asc */), (status_t)OK);
     } else {
         TRESPASS();  // XXX to be implemented
     }
 
     *frameLengthType = bits->getBits(3);
+    *fixedFrameLength = -1;
+
     switch (*frameLengthType) {
         case 0:
         {
@@ -260,7 +305,14 @@
 
         case 1:
         {
-            /* unsigned frameLength = */bits->getBits(9);
+            *fixedFrameLength = bits->getBits(9);
+            break;
+        }
+
+        case 2:
+        {
+            // reserved
+            TRESPASS();
             break;
         }
 
@@ -338,9 +390,21 @@
                 break;
             }
 
-            default:
-                TRESPASS();  // XXX to be implemented
+            case 2:
+            {
+                // reserved
+
+                TRESPASS();
                 break;
+            }
+
+            default:
+            {
+                CHECK_GE(mFixedFrameLength, 0);
+
+                payloadLength = mFixedFrameLength;
+                break;
+            }
         }
 
         CHECK_LE(offset + payloadLength, buffer->size());
@@ -393,6 +457,7 @@
     ABitReader bits(config->data(), config->size());
     status_t err = parseStreamMuxConfig(
             &bits, &mNumSubFrames, &mFrameLengthType,
+            &mFixedFrameLength,
             &mOtherDataPresent, &mOtherDataLenBits);
 
     CHECK_EQ(err, (status_t)NO_ERROR);
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.h b/media/libstagefright/rtsp/AMPEG4AudioAssembler.h
index 9cef94c..1361cd2 100644
--- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.h
+++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.h
@@ -46,6 +46,7 @@
     bool mMuxConfigPresent;
     unsigned mNumSubFrames;
     unsigned mFrameLengthType;
+    ssize_t mFixedFrameLength;
     bool mOtherDataPresent;
     unsigned mOtherDataLenBits;
 
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 679dcab..6819fef 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -20,6 +20,7 @@
 
 #include "APacketSource.h"
 
+#include "ARawAudioAssembler.h"
 #include "ASessionDescription.h"
 
 #include "avc_utils.h"
@@ -661,6 +662,8 @@
         mFormat->setData(
                 kKeyESDS, 0,
                 codecSpecificData->data(), codecSpecificData->size());
+    } else if (ARawAudioAssembler::Supports(desc.c_str())) {
+        ARawAudioAssembler::MakeFormat(desc.c_str(), mFormat);
     } else {
         mInitCheck = ERROR_UNSUPPORTED;
     }
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index 84c666f..3aa07ce 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -25,6 +25,7 @@
 #include "AH263Assembler.h"
 #include "AMPEG4AudioAssembler.h"
 #include "AMPEG4ElementaryAssembler.h"
+#include "ARawAudioAssembler.h"
 #include "ASessionDescription.h"
 
 #include <media/stagefright/foundation/ABuffer.h>
@@ -70,6 +71,8 @@
             || !strncasecmp(desc.c_str(), "mpeg4-generic/", 14)) {
         mAssembler = new AMPEG4ElementaryAssembler(notify, desc, params);
         mIssueFIRRequests = true;
+    } else if (ARawAudioAssembler::Supports(desc.c_str())) {
+        mAssembler = new ARawAudioAssembler(notify, desc.c_str(), params);
     } else {
         TRESPASS();
     }
diff --git a/media/libstagefright/rtsp/ARawAudioAssembler.cpp b/media/libstagefright/rtsp/ARawAudioAssembler.cpp
new file mode 100644
index 0000000..dd47ea3
--- /dev/null
+++ b/media/libstagefright/rtsp/ARawAudioAssembler.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ARawAudioAssembler"
+#include <utils/Log.h>
+
+#include "ARawAudioAssembler.h"
+
+#include "ARTPSource.h"
+#include "ASessionDescription.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/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+ARawAudioAssembler::ARawAudioAssembler(
+        const sp<AMessage> &notify, const char *desc, const AString &params)
+    : mNotifyMsg(notify),
+      mNextExpectedSeqNoValid(false),
+      mNextExpectedSeqNo(0) {
+}
+
+ARawAudioAssembler::~ARawAudioAssembler() {
+}
+
+ARTPAssembler::AssemblyStatus ARawAudioAssembler::assembleMore(
+        const sp<ARTPSource> &source) {
+    return addPacket(source);
+}
+
+ARTPAssembler::AssemblyStatus ARawAudioAssembler::addPacket(
+        const sp<ARTPSource> &source) {
+    List<sp<ABuffer> > *queue = source->queue();
+
+    if (queue->empty()) {
+        return NOT_ENOUGH_DATA;
+    }
+
+    if (mNextExpectedSeqNoValid) {
+        List<sp<ABuffer> >::iterator it = queue->begin();
+        while (it != queue->end()) {
+            if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) {
+                break;
+            }
+
+            it = queue->erase(it);
+        }
+
+        if (queue->empty()) {
+            return NOT_ENOUGH_DATA;
+        }
+    }
+
+    sp<ABuffer> buffer = *queue->begin();
+
+    if (!mNextExpectedSeqNoValid) {
+        mNextExpectedSeqNoValid = true;
+        mNextExpectedSeqNo = (uint32_t)buffer->int32Data();
+    } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) {
+        LOGV("Not the sequence number I expected");
+
+        return WRONG_SEQUENCE_NUMBER;
+    }
+
+    // hexdump(buffer->data(), buffer->size());
+
+    if (buffer->size() < 1) {
+        queue->erase(queue->begin());
+        ++mNextExpectedSeqNo;
+
+        LOGV("raw audio packet too short.");
+
+        return MALFORMED_PACKET;
+    }
+
+    sp<AMessage> msg = mNotifyMsg->dup();
+    msg->setObject("access-unit", buffer);
+    msg->post();
+
+    queue->erase(queue->begin());
+    ++mNextExpectedSeqNo;
+
+    return OK;
+}
+
+void ARawAudioAssembler::packetLost() {
+    CHECK(mNextExpectedSeqNoValid);
+    ++mNextExpectedSeqNo;
+}
+
+void ARawAudioAssembler::onByeReceived() {
+    sp<AMessage> msg = mNotifyMsg->dup();
+    msg->setInt32("eos", true);
+    msg->post();
+}
+
+// static
+bool ARawAudioAssembler::Supports(const char *desc) {
+    return !strncmp(desc, "PCMU/", 5)
+        || !strncmp(desc, "PCMA/", 5);
+}
+
+// static
+void ARawAudioAssembler::MakeFormat(
+        const char *desc, const sp<MetaData> &format) {
+    if (!strncmp(desc, "PCMU/", 5)) {
+        format->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_MLAW);
+    } else if (!strncmp(desc, "PCMA/", 5)) {
+        format->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_ALAW);
+    } else {
+        TRESPASS();
+    }
+
+    int32_t sampleRate, numChannels;
+    ASessionDescription::ParseFormatDesc(
+            desc, &sampleRate, &numChannels);
+
+    format->setInt32(kKeySampleRate, sampleRate);
+    format->setInt32(kKeyChannelCount, numChannels);
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/rtsp/ARawAudioAssembler.h b/media/libstagefright/rtsp/ARawAudioAssembler.h
new file mode 100644
index 0000000..ed7af080
--- /dev/null
+++ b/media/libstagefright/rtsp/ARawAudioAssembler.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef A_RAW_AUDIO_ASSEMBLER_H_
+
+#define A_RAW_AUDIO_ASSEMBLER_H_
+
+#include "ARTPAssembler.h"
+
+namespace android {
+
+struct AMessage;
+struct AString;
+struct MetaData;
+
+struct ARawAudioAssembler : public ARTPAssembler {
+    ARawAudioAssembler(
+            const sp<AMessage> &notify,
+            const char *desc, const AString &params);
+
+    static bool Supports(const char *desc);
+
+    static void MakeFormat(
+            const char *desc, const sp<MetaData> &format);
+
+protected:
+    virtual ~ARawAudioAssembler();
+
+    virtual AssemblyStatus assembleMore(const sp<ARTPSource> &source);
+    virtual void onByeReceived();
+    virtual void packetLost();
+
+private:
+    bool mIsWide;
+
+    sp<AMessage> mNotifyMsg;
+    bool mNextExpectedSeqNoValid;
+    uint32_t mNextExpectedSeqNo;
+
+    AssemblyStatus addPacket(const sp<ARTPSource> &source);
+
+    DISALLOW_EVIL_CONSTRUCTORS(ARawAudioAssembler);
+};
+
+}  // namespace android
+
+#endif  // A_RAW_AUDIO_ASSEMBLER_H_
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index fb42de8..8530ff3 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -9,6 +9,7 @@
         AMPEG4AudioAssembler.cpp    \
         AMPEG4ElementaryAssembler.cpp \
         APacketSource.cpp           \
+        ARawAudioAssembler.cpp      \
         ARTPAssembler.cpp           \
         ARTPConnection.cpp          \
         ARTPSource.cpp              \
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 853a5af..37e02a3 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -84,6 +84,8 @@
 static const MtpEventCode kSupportedEventCodes[] = {
     MTP_EVENT_OBJECT_ADDED,
     MTP_EVENT_OBJECT_REMOVED,
+    MTP_EVENT_STORE_ADDED,
+    MTP_EVENT_STORE_REMOVED,
 };
 
 MtpServer::MtpServer(int fd, MtpDatabase* database,
@@ -104,11 +106,23 @@
 MtpServer::~MtpServer() {
 }
 
-void MtpServer::addStorage(const char* filePath, uint64_t reserveSpace) {
-    int index = mStorages.size() + 1;
-    index |= index << 16;   // set high and low part to our index
-    MtpStorage* storage = new MtpStorage(index, filePath, reserveSpace);
-    addStorage(storage);
+void MtpServer::addStorage(MtpStorage* storage) {
+    Mutex::Autolock autoLock(mMutex);
+
+    mStorages.push(storage);
+    sendStoreAdded(storage->getStorageID());
+}
+
+void MtpServer::removeStorage(MtpStorage* storage) {
+    Mutex::Autolock autoLock(mMutex);
+
+    for (int i = 0; i < mStorages.size(); i++) {
+        if (mStorages[i] == storage) {
+            mStorages.removeAt(i);
+            sendStoreRemoved(storage->getStorageID());
+            break;
+        }
+    }
 }
 
 MtpStorage* MtpServer::getStorage(MtpStorageID id) {
@@ -122,6 +136,12 @@
     return NULL;
 }
 
+bool MtpServer::hasStorage(MtpStorageID id) {
+    if (id == 0 || id == 0xFFFFFFFF)
+        return mStorages.size() > 0;
+    return (getStorage(id) != NULL);
+}
+
 void MtpServer::run() {
     int fd = mFD;
 
@@ -203,28 +223,38 @@
 }
 
 void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
-    if (mSessionOpen) {
-        LOGV("sendObjectAdded %d\n", handle);
-        mEvent.setEventCode(MTP_EVENT_OBJECT_ADDED);
-        mEvent.setTransactionID(mRequest.getTransactionID());
-        mEvent.setParameter(1, handle);
-        int ret = mEvent.write(mFD);
-        LOGV("mEvent.write returned %d\n", ret);
-    }
+    LOGV("sendObjectAdded %d\n", handle);
+    sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
 }
 
 void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
+    LOGV("sendObjectRemoved %d\n", handle);
+    sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
+}
+
+void MtpServer::sendStoreAdded(MtpStorageID id) {
+    LOGV("sendStoreAdded %08X\n", id);
+    sendEvent(MTP_EVENT_STORE_ADDED, id);
+}
+
+void MtpServer::sendStoreRemoved(MtpStorageID id) {
+    LOGV("sendStoreRemoved %08X\n", id);
+    sendEvent(MTP_EVENT_STORE_REMOVED, id);
+}
+
+void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
     if (mSessionOpen) {
-        LOGV("sendObjectRemoved %d\n", handle);
-        mEvent.setEventCode(MTP_EVENT_OBJECT_REMOVED);
+        mEvent.setEventCode(code);
         mEvent.setTransactionID(mRequest.getTransactionID());
-        mEvent.setParameter(1, handle);
+        mEvent.setParameter(1, param1);
         int ret = mEvent.write(mFD);
         LOGV("mEvent.write returned %d\n", ret);
     }
 }
 
 bool MtpServer::handleRequest() {
+    Mutex::Autolock autoLock(mMutex);
+
     MtpOperationCode operation = mRequest.getOperationCode();
     MtpResponseCode response;
 
@@ -439,6 +469,9 @@
     MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
     MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
                                                             // 0x00000000 for all objects?
+
+    if (!hasStorage(storageID))
+        return MTP_RESPONSE_INVALID_STORAGE_ID;
     if (parent == 0xFFFFFFFF)
         parent = 0;
 
@@ -455,6 +488,8 @@
     MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
     MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
                                                             // 0x00000000 for all objects?
+    if (!hasStorage(storageID))
+        return MTP_RESPONSE_INVALID_STORAGE_ID;
     if (parent == 0xFFFFFFFF)
         parent = 0;
 
@@ -471,7 +506,9 @@
 MtpResponseCode MtpServer::doGetObjectReferences() {
     if (!mSessionOpen)
         return MTP_RESPONSE_SESSION_NOT_OPEN;
-    MtpStorageID handle = mRequest.getParameter(1);
+    if (!hasStorage())
+        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+    MtpObjectHandle handle = mRequest.getParameter(1);
 
     // FIXME - check for invalid object handle
     MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
@@ -487,7 +524,10 @@
 MtpResponseCode MtpServer::doSetObjectReferences() {
     if (!mSessionOpen)
         return MTP_RESPONSE_SESSION_NOT_OPEN;
+    if (!hasStorage())
+        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
     MtpStorageID handle = mRequest.getParameter(1);
+
     MtpObjectHandleList* references = mData.getAUInt32();
     MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
     delete references;
@@ -495,6 +535,8 @@
 }
 
 MtpResponseCode MtpServer::doGetObjectPropValue() {
+    if (!hasStorage())
+        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
     MtpObjectHandle handle = mRequest.getParameter(1);
     MtpObjectProperty property = mRequest.getParameter(2);
     LOGV("GetObjectPropValue %d %s\n", handle,
@@ -504,6 +546,8 @@
 }
 
 MtpResponseCode MtpServer::doSetObjectPropValue() {
+    if (!hasStorage())
+        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
     MtpObjectHandle handle = mRequest.getParameter(1);
     MtpObjectProperty property = mRequest.getParameter(2);
     LOGV("SetObjectPropValue %d %s\n", handle,
@@ -537,6 +581,8 @@
 }
 
 MtpResponseCode MtpServer::doGetObjectPropList() {
+    if (!hasStorage())
+        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
 
     MtpObjectHandle handle = mRequest.getParameter(1);
     // use uint32_t so we can support 0xFFFFFFFF
@@ -552,11 +598,15 @@
 }
 
 MtpResponseCode MtpServer::doGetObjectInfo() {
+    if (!hasStorage())
+        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
     MtpObjectHandle handle = mRequest.getParameter(1);
     return mDatabase->getObjectInfo(handle, mData);
 }
 
 MtpResponseCode MtpServer::doGetObject() {
+    if (!hasStorage())
+        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
     MtpObjectHandle handle = mRequest.getParameter(1);
     MtpString pathBuf;
     int64_t fileLength;
@@ -592,6 +642,8 @@
 }
 
 MtpResponseCode MtpServer::doGetPartialObject() {
+    if (!hasStorage())
+        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
     MtpObjectHandle handle = mRequest.getParameter(1);
     uint32_t offset = mRequest.getParameter(2);
     uint32_t length = mRequest.getParameter(3);
@@ -688,6 +740,7 @@
     if (mSendObjectFileSize > storage->getFreeSpace())
         return MTP_RESPONSE_STORAGE_FULL;
 
+LOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
     MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
             format, parent, storageID, mSendObjectFileSize, modifiedTime);
     if (handle == kInvalidObjectHandle) {
@@ -719,6 +772,8 @@
 }
 
 MtpResponseCode MtpServer::doSendObject() {
+    if (!hasStorage())
+        return MTP_RESPONSE_GENERAL_ERROR;
     MtpResponseCode result = MTP_RESPONSE_OK;
     mode_t mask;
     int ret;
@@ -835,6 +890,8 @@
 }
 
 MtpResponseCode MtpServer::doDeleteObject() {
+    if (!hasStorage())
+        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
     MtpObjectHandle handle = mRequest.getParameter(1);
     MtpObjectFormat format = mRequest.getParameter(2);
     // FIXME - support deleting all objects if handle is 0xFFFFFFFF
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index 605d5a2..1efa715 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -22,9 +22,10 @@
 #include "MtpResponsePacket.h"
 #include "MtpEventPacket.h"
 #include "mtp.h"
-
 #include "MtpUtils.h"
 
+#include <utils/threads.h>
+
 namespace android {
 
 class MtpDatabase;
@@ -62,20 +63,29 @@
     MtpString           mSendObjectFilePath;
     size_t              mSendObjectFileSize;
 
+    Mutex               mMutex;
+
 public:
                         MtpServer(int fd, MtpDatabase* database,
                                     int fileGroup, int filePerm, int directoryPerm);
     virtual             ~MtpServer();
 
-    void                addStorage(const char* filePath, uint64_t reserveSpace);
-    inline void         addStorage(MtpStorage* storage) { mStorages.push(storage); }
-    MtpStorage*         getStorage(MtpStorageID id);
+    void                addStorage(MtpStorage* storage);
+    void                removeStorage(MtpStorage* storage);
+
     void                run();
 
     void                sendObjectAdded(MtpObjectHandle handle);
     void                sendObjectRemoved(MtpObjectHandle handle);
 
 private:
+    MtpStorage*         getStorage(MtpStorageID id);
+    inline bool         hasStorage() { return mStorages.size() > 0; }
+    bool                hasStorage(MtpStorageID id);
+    void                sendStoreAdded(MtpStorageID id);
+    void                sendStoreRemoved(MtpStorageID id);
+    void                sendEvent(MtpEventCode code, uint32_t param1);
+
     bool                handleRequest();
 
     MtpResponseCode     doGetDeviceInfo();
diff --git a/media/mtp/MtpStorage.cpp b/media/mtp/MtpStorage.cpp
index 2fbbc51..6cb88b3 100644
--- a/media/mtp/MtpStorage.cpp
+++ b/media/mtp/MtpStorage.cpp
@@ -59,7 +59,7 @@
 uint64_t MtpStorage::getMaxCapacity() {
     if (mMaxCapacity == 0) {
         struct statfs   stat;
-        if (statfs(mFilePath, &stat))
+        if (statfs(getPath(), &stat))
             return -1;
         mMaxCapacity = (uint64_t)stat.f_blocks * (uint64_t)stat.f_bsize;
     }
@@ -68,7 +68,7 @@
 
 uint64_t MtpStorage::getFreeSpace() {
     struct statfs   stat;
-    if (statfs(mFilePath, &stat))
+    if (statfs(getPath(), &stat))
         return -1;
     uint64_t freeSpace = (uint64_t)stat.f_bavail * (uint64_t)stat.f_bsize;
     return (freeSpace > mReserveSpace ? freeSpace - mReserveSpace : 0);
diff --git a/media/mtp/MtpStorage.h b/media/mtp/MtpStorage.h
index ace720b..858c9d3 100644
--- a/media/mtp/MtpStorage.h
+++ b/media/mtp/MtpStorage.h
@@ -17,6 +17,7 @@
 #ifndef _MTP_STORAGE_H
 #define _MTP_STORAGE_H
 
+#include "MtpTypes.h"
 #include "mtp.h"
 
 namespace android {
@@ -27,7 +28,7 @@
 
 private:
     MtpStorageID            mStorageID;
-    const char*             mFilePath;
+    MtpString               mFilePath;
     uint64_t                mMaxCapacity;
     // amount of free space to leave unallocated
     uint64_t                mReserveSpace;
@@ -44,7 +45,7 @@
     uint64_t                getMaxCapacity();
     uint64_t                getFreeSpace();
     const char*             getDescription() const;
-    inline const char*      getPath() const { return mFilePath; }
+    inline const char*      getPath() const { return (const char *)mFilePath; }
 };
 
 }; // namespace android
diff --git a/media/mtp/mtp.h b/media/mtp/mtp.h
index 8bc2e22..6fedc16 100644
--- a/media/mtp/mtp.h
+++ b/media/mtp/mtp.h
@@ -22,6 +22,8 @@
 
 #define MTP_STANDARD_VERSION            100
 
+#define MTP_FIRST_STORAGE_ID            0x00010001
+
 // Container Types
 #define MTP_CONTAINER_TYPE_UNDEFINED    0
 #define MTP_CONTAINER_TYPE_COMMAND      1
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java
index eaaa798..988b229 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java
@@ -17,7 +17,8 @@
 package com.android.mediaframeworktest;
 
 import com.android.mediaframeworktest.performance.MediaPlayerPerformance;
-
+/*Video Editor performance Test cases*/
+import com.android.mediaframeworktest.performance.VideoEditorPerformance;
 import junit.framework.TestSuite;
 
 import android.test.InstrumentationTestRunner;
@@ -26,7 +27,7 @@
 
 /**
  * Instrumentation Test Runner for all MediaPlayer tests.
- * 
+ *
  * Running all tests:
  *
  * adb shell am instrument \
@@ -40,6 +41,8 @@
   public TestSuite getAllTests() {
       TestSuite suite = new InstrumentationTestSuite(this);
       suite.addTestSuite(MediaPlayerPerformance.class);
+      /*Video Editor performance Test cases*/
+      suite.addTestSuite(VideoEditorPerformance.class);
       return suite;
   }
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaPlayerStressTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaPlayerStressTestRunner.java
index 5438061..0cd784c 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaPlayerStressTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaPlayerStressTestRunner.java
@@ -19,6 +19,8 @@
 import android.test.InstrumentationTestRunner;
 import android.test.InstrumentationTestSuite;
 import com.android.mediaframeworktest.stress.MediaPlayerStressTest;
+/** Import for Video Editor Stress Test cases*/
+import com.android.mediaframeworktest.stress.VideoEditorStressTest;
 
 import junit.framework.TestSuite;
 
@@ -28,6 +30,8 @@
     public TestSuite getAllTests() {
         TestSuite suite = new InstrumentationTestSuite(this);
         suite.addTestSuite(MediaPlayerStressTest.class);
+        /** Video Editor Stress Test cases*/
+        suite.addTestSuite(VideoEditorStressTest.class);
         return suite;
     }
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorPreviewTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorPreviewTest.java
index bd0a838..9a7f4f2 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorPreviewTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/VideoEditorPreviewTest.java
@@ -95,7 +95,7 @@
     private boolean previewStop;
 
     /* Minimum waiting time for Semaphore to wait for release */
-    private final long minWaitingTime = 1000;
+    private final long minWaitingTime = 3000;
 
     // Declares the annotation for Preview Test Cases
     public @interface Preview {
@@ -473,8 +473,8 @@
         mVideoEditorHelper.checkProgressCBValues(progressValues);
         final SurfaceHolder surfaceHolder =
             MediaFrameworkTest.mSurfaceView.getHolder();
-
-        long waitingTime = minWaitingTime + 10000;
+        /* As transition takes more time buffer of 10 sec is added */
+        long waitingTime = minWaitingTime + 10000 + 10000;
 
         blockTillPreviewCompletes.acquire();
         try {
@@ -691,31 +691,34 @@
 
         long waitingTime = minWaitingTime + mVideoEditor.getDuration();
 
+
         blockTillPreviewCompletes.acquire();
+                    final String fileName = mVideoEditor.getPath() + "\test.3gp";
+                    final int height = MediaProperties.HEIGHT_480;
+                    final int bitrate = MediaProperties.BITRATE_512K;
+
+            try {
+                mVideoEditor.export(fileName, height, bitrate,
+                    new ExportProgressListener() {
+                        public void onProgress(VideoEditor ve,
+                            String outFileName,int progress) {
+
+                        }
+                    });
+            } catch (IOException e) {
+                assertTrue("UnExpected Error in Export" +
+                    e.toString(), false);
+            }
 
         final SurfaceHolder surfaceHolder =
             MediaFrameworkTest.mSurfaceView.getHolder();
         try {
+
             mVideoEditor.startPreview(surfaceHolder, 5000, -1, false, 1,
                 new PreviewProgressListener() {
-                    final String fileName = mVideoEditor.getPath() + "\test.3gp";
-                    final int height = MediaProperties.HEIGHT_360;
-                    final int bitrate = MediaProperties.BITRATE_512K;
+
                     public void onProgress(VideoEditor videoEditor, long timeMs,
                         OverlayData overlayData) {
-                            if (timeMs >= 10000)
-                            try {
-                                videoEditor.export(fileName, height, bitrate,
-                                    new ExportProgressListener() {
-                                        public void onProgress(VideoEditor ve,
-                                            String outFileName,int progress) {
-
-                                        }
-                                    });
-                            } catch (IOException e) {
-                                assertTrue("UnExpected Error in Export" +
-                                    e.toString(), false);
-                        }
                     }
                 public void onStart(VideoEditor videoEditor) {
                     setPreviewStart();
@@ -725,10 +728,10 @@
                     blockTillPreviewCompletes.release();
                 }
             });
+
         } catch (Exception e) {
             blockTillPreviewCompletes.release();
         }
-
         blockTillPreviewCompletes.tryAcquire(waitingTime, TimeUnit.MILLISECONDS);
         mVideoEditor.stopPreview();
         assertTrue("Preview Failed to start", previewStart);
@@ -837,31 +840,7 @@
             mVideoEditor.renderPreviewFrame(surfaceHolder, 7000,
             overlayData1));
 
-        long waitingTime = minWaitingTime + (mVideoEditor.getDuration() - 5000);
-
-        blockTillPreviewCompletes.acquire();
-        try {
-            mVideoEditor.startPreview(surfaceHolder, 5000, -1, false, 1,
-                new PreviewProgressListener() {
-                    public void onProgress(VideoEditor videoEditor, long timeMs,
-                        OverlayData overlayData) {
-                    }
-                    public void onStart(VideoEditor videoEditor) {
-                        setPreviewStart();
-                    }
-                    public void onStop(VideoEditor videoEditor) {
-                        setPreviewStop();
-                        blockTillPreviewCompletes.release();
-                    }
-            });
-        } catch (Exception e) {
-            blockTillPreviewCompletes.release();
-        }
-        blockTillPreviewCompletes.tryAcquire(waitingTime, TimeUnit.MILLISECONDS);
-        mVideoEditor.stopPreview();
-        assertTrue("Preview Failed to start", previewStart);
-        assertTrue("Preview Failed to stop", previewStop);
-        blockTillPreviewCompletes.release();
+        validatePreviewProgress(5000, -1, false, mVideoEditor.getDuration());
     }
 
     /**
@@ -1142,20 +1121,19 @@
         duration = mVideoEditor.getDuration();
         /* RenderPreviewFrame returns -1 to indicate last frame */
         try {
-        assertEquals("Render preview Frame at item duration", -1,
-            mVideoEditor.renderPreviewFrame(surfaceHolder, duration,
-            overlayData1));
-        } catch ( Exception e) {
-            assertTrue (" Render Preview Frame without generate", false);
-        }
-        duration = mVideoEditor.getDuration() + 1000;
-        try {
             mVideoEditor.renderPreviewFrame(surfaceHolder, duration,
             overlayData1);
         } catch ( IllegalStateException e) {
             flagForException = true;
         }
+        assertTrue (" Render Preview Frame without generate", flagForException);
+        duration = mVideoEditor.getDuration() + 1000;
+        try {
+            mVideoEditor.renderPreviewFrame(surfaceHolder, duration,
+            overlayData1);
+        } catch ( IllegalArgumentException e) {
+            flagForException = true;
+        }
         assertTrue (" Preview time greater than duration", flagForException);
     }
-
 }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/VideoEditorPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/VideoEditorPerformance.java
new file mode 100644
index 0000000..4481d00
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/VideoEditorPerformance.java
@@ -0,0 +1,1086 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.mediaframeworktest.performance;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.Writer;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.media.videoeditor.AudioTrack;
+import android.media.videoeditor.EffectColor;
+import android.media.videoeditor.EffectKenBurns;
+import android.media.videoeditor.MediaImageItem;
+import android.media.videoeditor.MediaItem;
+import android.media.videoeditor.MediaProperties;
+import android.media.videoeditor.MediaVideoItem;
+import android.media.videoeditor.OverlayFrame;
+import android.media.videoeditor.Transition;
+import android.media.videoeditor.TransitionCrossfade;
+import android.media.videoeditor.TransitionAlpha;
+import android.media.videoeditor.TransitionFadeBlack;
+import android.media.videoeditor.TransitionSliding;
+import android.media.videoeditor.VideoEditor;
+import android.os.Environment;
+import android.test.ActivityInstrumentationTestCase;
+import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener;
+import android.os.Environment;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase;
+import android.media.videoeditor.VideoEditor.ExportProgressListener;
+
+import android.util.Log;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import com.android.mediaframeworktest.VideoEditorHelper;
+
+/**
+ * Junit / Instrumentation - performance measurement for media player and
+ * recorder
+ */
+public class VideoEditorPerformance extends
+    ActivityInstrumentationTestCase<MediaFrameworkTest> {
+
+    private final String TAG = "VideoEditorPerformance";
+
+    private final String PROJECT_LOCATION = VideoEditorHelper.PROJECT_LOCATION_COMMON;
+
+    private final String INPUT_FILE_PATH = VideoEditorHelper.INPUT_FILE_PATH_COMMON;
+
+    private final String VIDEOEDITOR_OUTPUT = PROJECT_LOCATION +
+        "VideoEditorPerformance.txt";
+
+    public VideoEditorPerformance() {
+        super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+    }
+
+    private final String PROJECT_CLASS_NAME =
+        "android.media.videoeditor.VideoEditorImpl";
+    private VideoEditor mVideoEditor;
+    private VideoEditorHelper mVideoEditorHelper;
+
+    @Override
+    protected void setUp() throws Exception {
+        // setup for each test case.
+        super.setUp();
+        mVideoEditorHelper = new VideoEditorHelper();
+        // Create a random String which will be used as project path, where all
+        // project related files will be stored.
+        final String projectPath =
+            mVideoEditorHelper.createRandomFile(PROJECT_LOCATION);
+        mVideoEditor = mVideoEditorHelper.createVideoEditor(projectPath);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mVideoEditorHelper.destroyVideoEditor(mVideoEditor);
+        // Clean the directory created as project path
+        mVideoEditorHelper.deleteProject(new File(mVideoEditor.getPath()));
+        System.gc();
+        super.tearDown();
+    }
+
+    private void writeTimingInfo(String testCaseName, String[] information)
+        throws Exception {
+        File outFile = new File(VIDEOEDITOR_OUTPUT);
+        Writer output = new BufferedWriter(new FileWriter(outFile, true));
+        output.write(testCaseName + "\n\t");
+        for (int i = 0; i < information.length; i++) {
+            output.write(information[i]);
+        }
+        output.write("\n\n");
+        output.close();
+    }
+
+    private final int NUM_OF_ITERATIONS=20;
+
+    private float calculateTimeTaken(long beginTime, int numIterations)
+        throws Exception {
+        final long duration2 = SystemClock.uptimeMillis();
+        final long durationToCreateMediaItem = (duration2 - beginTime);
+        final float timeTaken1 = (float)durationToCreateMediaItem *
+            1.0f/(float)numIterations;
+        return (timeTaken1);
+    }
+
+    private void createVideoItems(MediaVideoItem[] mediaVideoItem,
+        String videoItemFileName, int renderingMode, int startTime, int endTime) throws Exception {
+        for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
+            try {
+                mediaVideoItem[i] = new MediaVideoItem(mVideoEditor, "m" + i,
+                    videoItemFileName, renderingMode);
+                mediaVideoItem[i].setExtractBoundaries(startTime, endTime);
+            } catch (Exception e1) {
+                assertTrue(
+                    "Can not create an object of Video Item with file name = "
+                    + videoItemFileName + "------ID:m" + i + "       Issue = "
+                    + e1.toString(), false);
+            }
+        }
+    }
+
+    private void addVideoItems(MediaVideoItem[] mediaVideoItem) throws Exception {
+        for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
+            try {
+                mVideoEditor.addMediaItem(mediaVideoItem[i]);
+            } catch (Exception e1) {
+                assertTrue(
+                    "Can not add an object of Video Item with ID:m" + i +
+                    "    Issue = " + e1.toString(), false);
+            }
+        }
+    }
+
+    private void removeVideoItems(MediaVideoItem[] mediaVideoItem) throws Exception {
+            for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
+            try {
+            mVideoEditor.removeMediaItem(mediaVideoItem[i].getId());
+            } catch (Exception e1) {
+                assertTrue(
+                    "Can not Remove an object of Video Item with ID:m" + i +
+                    "    Issue = " + e1.toString(), false);
+            }
+        }
+    }
+
+    private void createImageItems(MediaImageItem[] mIi,
+        String imageItemFileName, int renderingMode, int duration) throws Exception {
+        for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
+            try {
+                mIi[i] = new MediaImageItem(mVideoEditor, "m" + i,
+                    imageItemFileName, duration, renderingMode);
+            } catch (Exception e1) {
+                assertTrue( " Cannot create Image Item", false);
+            }
+        }
+    }
+
+    private void addImageItems(MediaImageItem[] mIi) throws Exception {
+        for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
+            try {
+                mVideoEditor.addMediaItem(mIi[i]);
+            } catch (Exception e1) {
+                assertTrue("Cannot add Image item", false);
+            }
+        }
+    }
+
+    private void removeImageItems(MediaImageItem[] mIi) throws Exception {
+            for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
+            try {
+            mVideoEditor.removeMediaItem(mIi[i].getId());
+            } catch (Exception e1) {
+                assertTrue("Cannot remove image item", false);
+            }
+        }
+    }
+    /**
+     * To test the performance of adding and removing the video media item
+     *
+     * @throws Exception
+     */
+    // TODO : remove PRF_001
+    @LargeTest
+    public void testPerformanceAddRemoveVideoItem() throws Exception {
+        final String videoItemFileName = INPUT_FILE_PATH +
+            "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
+        final int videoItemStartTime = 0;
+        final int videoItemEndTime = 5000;
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String[] loggingInfo = new String[3];
+        final MediaVideoItem[] mediaVideoItem =
+            new MediaVideoItem[NUM_OF_ITERATIONS];
+        float timeTaken = 0.0f;
+        long startTime = 0;
+
+        /** Time Take for creation of Media Video Item */
+        startTime = SystemClock.uptimeMillis();
+        createVideoItems(mediaVideoItem, videoItemFileName, renderingMode,
+            videoItemStartTime, videoItemEndTime);
+
+        timeTaken = calculateTimeTaken (startTime, NUM_OF_ITERATIONS);
+        loggingInfo[0] = "Time taken to Create Media Video Item\t" +
+            timeTaken;
+
+        /** Time Take for Addition of Media Video Item */
+        startTime = SystemClock.uptimeMillis();
+        addVideoItems(mediaVideoItem);
+        timeTaken = calculateTimeTaken (startTime, NUM_OF_ITERATIONS);
+        loggingInfo[1] = "\n\tTime taken to Add  Media Video Item\t"
+            + timeTaken;
+
+        /** Time Take for Removal of Media Video Item */
+        startTime = SystemClock.uptimeMillis();
+        removeVideoItems(mediaVideoItem);
+        timeTaken = calculateTimeTaken (startTime, NUM_OF_ITERATIONS);
+        loggingInfo[2] = "\n\tTime taken to remove  Media Video Item\t"
+            + timeTaken;
+
+        writeTimingInfo("testPerformanceAddRemoveVideoItem (in mSec)", loggingInfo);
+    }
+
+    /**
+     * To test the performance of adding and removing the image media item
+     *
+     * @throws Exception
+     */
+    // TODO : remove PRF_002
+    @LargeTest
+    public void testPerformanceAddRemoveImageItem() throws Exception {
+        final String imageItemFileName = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
+        final int imageItemDuration = 0;
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String[] loggingInfo = new String[3];
+        final MediaImageItem[] mediaImageItem =
+            new MediaImageItem[NUM_OF_ITERATIONS];
+        float timeTaken = 0.0f;
+
+        long beginTime = SystemClock.uptimeMillis();
+        createImageItems(mediaImageItem, imageItemFileName, renderingMode,
+            imageItemDuration);
+        timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
+        loggingInfo[0] = "Time taken to Create  Media Image Item\t" +
+            timeTaken;
+
+        beginTime = SystemClock.uptimeMillis();
+        addImageItems(mediaImageItem);
+        timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
+        loggingInfo[1] = "\n\tTime taken to add  Media Image Item\t" +
+            timeTaken;
+
+        beginTime = SystemClock.uptimeMillis();
+        removeImageItems(mediaImageItem);
+        timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
+        loggingInfo[2] = "\n\tTime taken to remove  Media Image Item\t"
+            + timeTaken;
+
+        writeTimingInfo("testPerformanceAddRemoveImageItem (in mSec)",
+            loggingInfo);
+    }
+
+    /**
+     * To test the performance of adding and removing the transition
+     *
+     * @throws Exception
+     */
+    // TODO : remove PRF_003
+    @LargeTest
+    public void testPerformanceAddRemoveTransition() throws Exception {
+        final String videoItemFileName1 = INPUT_FILE_PATH +
+        "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
+        final int videoItemStartTime1 = 0;
+        final int videoItemEndTime1 = 20000;
+        final String videoItemFileName2 = INPUT_FILE_PATH
+            + "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
+        final int videoItemStartTime2 = 0;
+        final int videoItemEndTime2 = 20000;
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final int transitionDuration = 5000;
+        final int transitionBehavior = Transition.BEHAVIOR_MIDDLE_FAST;
+        final String[] loggingInfo = new String[3];
+        float timeTaken = 0.0f;
+
+        final MediaVideoItem[] mediaVideoItem =
+            new MediaVideoItem[(NUM_OF_ITERATIONS *10) + 1];
+
+        for (int i = 0; i < (NUM_OF_ITERATIONS *10); i+=2) {
+            try {
+                mediaVideoItem[i] = new MediaVideoItem(mVideoEditor, "m" + i,
+                    videoItemFileName1, renderingMode);
+                mediaVideoItem[i+1] = new MediaVideoItem(mVideoEditor,
+                    "m" + (i+1), videoItemFileName2, renderingMode);
+                mediaVideoItem[i].setExtractBoundaries(videoItemStartTime1,
+                    videoItemEndTime1);
+                mediaVideoItem[i+1].setExtractBoundaries(videoItemStartTime2,
+                    videoItemEndTime2);
+            } catch (Exception e1) {
+                assertTrue("Can not create Video Object Item with file name = "
+                    + e1.toString(), false);
+            }
+            mVideoEditor.addMediaItem(mediaVideoItem[i]);
+            mVideoEditor.addMediaItem(mediaVideoItem[i+1]);
+        }
+        mediaVideoItem[(NUM_OF_ITERATIONS *10)] = new MediaVideoItem(mVideoEditor,
+            "m" + (NUM_OF_ITERATIONS *10), videoItemFileName1, renderingMode);
+        mediaVideoItem[(NUM_OF_ITERATIONS *10)].setExtractBoundaries(
+            videoItemStartTime1, videoItemEndTime1);
+        mVideoEditor.addMediaItem(mediaVideoItem[(NUM_OF_ITERATIONS *10)]);
+        final TransitionCrossfade tranCrossfade[] =
+            new TransitionCrossfade[(NUM_OF_ITERATIONS *10)];
+
+        long beginTime = SystemClock.uptimeMillis();
+        for (int i = 0; i < (NUM_OF_ITERATIONS *10); i++) {
+            tranCrossfade[i] = new TransitionCrossfade("transition" + i,
+                mediaVideoItem[i], mediaVideoItem[i+1], transitionDuration,
+                transitionBehavior);
+        }
+        timeTaken = calculateTimeTaken(beginTime, (NUM_OF_ITERATIONS * 10));
+        loggingInfo[0] = "Time taken to Create CrossFade Transition\t" +
+            timeTaken;
+
+        beginTime = SystemClock.uptimeMillis();
+        for (int i = 0; i < (NUM_OF_ITERATIONS *10); i++) {
+            mVideoEditor.addTransition(tranCrossfade[i]);
+        }
+        timeTaken = calculateTimeTaken(beginTime, (NUM_OF_ITERATIONS * 10));
+        loggingInfo[1] = "\n\tTime taken to add CrossFade Transition\t" +
+            timeTaken;
+
+        beginTime = SystemClock.uptimeMillis();
+        for (int i = 0; i < (NUM_OF_ITERATIONS *10); i++) {
+            assertEquals("Removing Transitions", tranCrossfade[i], mVideoEditor
+                .removeTransition(tranCrossfade[i].getId()));
+        }
+        timeTaken = calculateTimeTaken(beginTime, (NUM_OF_ITERATIONS * 10));
+        loggingInfo[2] = "\n\tTime taken to remove CrossFade Transition\t" +
+            timeTaken;
+
+        writeTimingInfo("testPerformanceAddRemoveTransition (in mSec)", loggingInfo);
+    }
+
+    /**
+     * To test performance of Export
+     *
+     * @throws Exception
+     */
+    // TODO : remove PRF_004
+    @LargeTest
+    public void testPerformanceExport() throws Exception {
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final int outHeight = MediaProperties.HEIGHT_480;
+        final int outBitrate = MediaProperties.BITRATE_256K;
+        final int outVcodec = MediaProperties.VCODEC_H264BP;
+        final String[] loggingInfo = new String[1];
+        final String outFilename = mVideoEditorHelper
+            .createRandomFile(mVideoEditor.getPath() + "/") + ".3gp";
+        final String videoItemFileName1 = INPUT_FILE_PATH +
+            "H264_BP_1080x720_30fps_12Mbps_AACLC_44.1khz_64kbps_s_1_17.mp4";
+        final String imageItemFileName1 = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
+        final String videoItemFileName2 = INPUT_FILE_PATH +
+            "H264_BP_640x480_15fps_1200Kbps_AACLC_48KHz_32kbps_m_1_17.3gp";
+        final String imageItemFileName2 = INPUT_FILE_PATH + "IMG_176x144.jpg";
+        final String videoItemFileName3 = INPUT_FILE_PATH +
+            "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_161kbps_s_0_26.mp4";
+        final String overlayFile = INPUT_FILE_PATH + "IMG_640x480_Overlay1.png";
+        final String audioTrackFilename = INPUT_FILE_PATH +
+            "AMRNB_8KHz_12.2Kbps_m_1_17.3gp";
+        final String maskFilename = INPUT_FILE_PATH +
+            "TransitionSpiral_QVGA.jpg";
+
+        final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
+            "m1", videoItemFileName1, renderingMode);
+        mediaItem1.setExtractBoundaries(0, 20000);
+        mVideoEditor.addMediaItem(mediaItem1);
+
+        final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
+            "m2", imageItemFileName1, 10000, renderingMode);
+        mVideoEditor.addMediaItem(mediaItem2);
+
+        final MediaVideoItem mediaItem3 = new MediaVideoItem(mVideoEditor,
+            "m3", videoItemFileName2, renderingMode);
+        mediaItem3.setExtractBoundaries(0, 20000);
+        mVideoEditor.addMediaItem(mediaItem3);
+
+        final MediaImageItem mediaItem4 = new MediaImageItem(mVideoEditor,
+            "m4", imageItemFileName2, 10000, renderingMode);
+        mVideoEditor.addMediaItem(mediaItem4);
+
+        final MediaVideoItem mediaItem5 = new MediaVideoItem(mVideoEditor,
+            "m5", videoItemFileName3, renderingMode);
+        mediaItem5.setExtractBoundaries(0, 20000);
+        mVideoEditor.addMediaItem(mediaItem5);
+        /**
+         * 7.Add TransitionAlpha, Apply this  Transition as Begin for Media Item 1
+         *  with duration = 2 sec behavior = BEHAVIOR_LINEAR, mask file name =
+         * TransitionSpiral_QVGA.jpg , blending percent = 50%, invert = true;
+         * */
+        final TransitionAlpha transition1 =
+            mVideoEditorHelper.createTAlpha("transition1", null, mediaItem1,
+                2000, Transition.BEHAVIOR_LINEAR, maskFilename, 50, true);
+        mVideoEditor.addTransition(transition1);
+
+        /**
+         * 8.Add Transition Sliding between MediaItem 2 and 3 ,
+         *  Sliding Direction  = DIRECTION_RIGHT_OUT_LEFT_IN,
+         *  behavior  = BEHAVIOR_MIDDLE_FAST and duration = 4sec
+         * */
+        final TransitionSliding transition2And3 =
+            mVideoEditorHelper.createTSliding("transition2", mediaItem2,
+                mediaItem3, 4000, Transition.BEHAVIOR_MIDDLE_FAST,
+                TransitionSliding.DIRECTION_RIGHT_OUT_LEFT_IN);
+        mVideoEditor.addTransition(transition2And3);
+
+        /**
+         * 9.Add Transition Crossfade between  Media Item 3 and 4,
+         *  behavior = BEHAVIOR_MIDDLE_SLOW, duration = 3.5 sec
+         * */
+        final TransitionCrossfade transition3And4 =
+            mVideoEditorHelper.createTCrossFade("transition3", mediaItem3,
+                mediaItem4, 3500, Transition.BEHAVIOR_MIDDLE_SLOW);
+        mVideoEditor.addTransition(transition3And4);
+
+        /**
+         * 10.Add Transition Fadeblack between  Media Item 4 and 5,
+         *  behavior = BEHAVIOR_SPEED_DOWN, duration = 3.5 sec
+         * */
+        final TransitionFadeBlack transition4And5 =
+            mVideoEditorHelper.createTFadeBlack("transition4", mediaItem4,
+                mediaItem5, 3500, Transition.BEHAVIOR_SPEED_DOWN);
+        mVideoEditor.addTransition(transition4And5);
+
+        /**
+         * 11.Add Effect 1 type="TYPE_SEPIA" to the MediaItem 1,
+         *  start time=1sec and duration =4secs
+         * */
+        final EffectColor effectColor1 = mVideoEditorHelper.createEffectItem(
+            mediaItem1, "effect1", 1000, 4000, EffectColor.TYPE_SEPIA, 0);
+        mediaItem1.addEffect(effectColor1);
+
+        /**
+         * 12.Add Overlay 1  to the MediaItem 3: Frame Overlay with start time = 1 sec
+         * duration = 4 sec with item  = IMG_640x480_Overlay1.png
+         * */
+        final Bitmap mBitmap =  mVideoEditorHelper.getBitmap(overlayFile, 640,
+            480);
+        final OverlayFrame overlayFrame =
+            mVideoEditorHelper.createOverlay(mediaItem3, "overlay",
+                mBitmap, 1000, 4000);
+        mediaItem3.addOverlay(overlayFrame);
+        /**
+         * 13.Add Effect 2 type="TYPE_NEGATIVE" to the MediaItem 2,
+         *  start time=8sec and duration =2secs
+         * */
+        final EffectColor effectColor2 = mVideoEditorHelper.createEffectItem(
+            mediaItem2, "effect2", 8000, 2000, EffectColor.TYPE_NEGATIVE, 0);
+        mediaItem2.addEffect(effectColor2);
+        /**
+         * 14.Add Effect 3 type="TYPE_COLOR" to the MediaItem 3, color param = "PINK",
+         *  start time=5 sec and duration =3secs
+         * */
+        final EffectColor effectColor3 = mVideoEditorHelper.createEffectItem(
+            mediaItem3, "effect3", 5000, 3000, EffectColor.TYPE_COLOR,
+            EffectColor.PINK);
+        mediaItem3.addEffect(effectColor3);
+        /**
+         * 15.Add Effect 4 type="TYPE_FIFTIES" to the MediaItem 4,
+         *  start time=2 sec and duration =1secs
+        * */
+        final EffectColor effectColor4 = mVideoEditorHelper.createEffectItem(
+            mediaItem4, "effect4", 2000, 1000, EffectColor.TYPE_FIFTIES, 0);
+        mediaItem4.addEffect(effectColor4);
+        /**
+         * 16.Add KenBurnsEffect for MediaItem 4 with
+         *  duration = 3 sec and startTime = 4 sec
+         *  StartRect
+         *  left = org_height/3  ;  top = org_width/3
+         *  bottom = org_width/2  ;  right = org_height/2
+         *  EndRect
+         *  left = 0  ;  top = 0
+         *  bottom =  org_height;  right =  org_width
+         * */
+
+        final Rect startRect = new Rect((mediaItem4.getHeight() / 3),
+            (mediaItem4.getWidth() / 3), (mediaItem4.getHeight() / 2),
+            (mediaItem4.getWidth() / 2));
+        final Rect endRect = new Rect(0, 0, mediaItem4.getWidth(),
+            mediaItem4.getHeight());
+        final EffectKenBurns kbEffectOnMediaItem = new EffectKenBurns(
+            mediaItem4, "KBOnM2", startRect, endRect,4000 , 3000);
+        mediaItem4.addEffect(kbEffectOnMediaItem);
+
+        /** 17.Add Audio Track,Set extract boundaries o to 10 sec.
+         * */
+        final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
+            mVideoEditor, "audioTrack", audioTrackFilename);
+        mVideoEditor.addAudioTrack(audioTrack);
+        /** 18.Enable Looping for Audio Track.
+         * */
+        audioTrack.enableLoop();
+        float timeTaken = 0.0f;
+        final long beginTime = SystemClock.uptimeMillis();
+            try {
+                mVideoEditor.export(outFilename, outHeight, outBitrate,
+                    new ExportProgressListener() {
+                        public void onProgress(VideoEditor ve,
+                            String outFileName, int progress) {
+                        }
+                    });
+            } catch (Exception e) {
+                assertTrue("Error in Export" + e.toString(), false);
+            }
+        mVideoEditorHelper.checkDeleteExistingFile(outFilename);
+
+        timeTaken = calculateTimeTaken(beginTime, 1);
+        loggingInfo[0] = "Time taken to do ONE export of storyboard duration\t"
+            + mVideoEditor.getDuration() + "   is   :\t" + timeTaken;
+
+        writeTimingInfo("testPerformanceExport (in mSec)", loggingInfo);
+        mVideoEditorHelper.deleteProject(new File(mVideoEditor.getPath()));
+    }
+
+
+    /**
+     * To test the performance of thumbnail extraction
+     *
+     * @throws Exception
+     */
+    // TODO : remove PRF_005
+    @LargeTest
+    public void testPerformanceThumbnailVideoItem() throws Exception {
+        final String videoItemFileName = INPUT_FILE_PATH
+            + "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
+        final int videoItemStartTime = 0;
+        final int videoItemEndTime = 20000;
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String[] loggingInfo = new String[1];
+
+        final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
+            "m1", videoItemFileName, renderingMode);
+        mediaVideoItem.setExtractBoundaries(videoItemStartTime,
+            videoItemEndTime);
+
+        float timeTaken = 0.0f;
+        long beginTime = SystemClock.uptimeMillis();
+        for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
+            mediaVideoItem.getThumbnail(mediaVideoItem.getWidth() / 2,
+                mediaVideoItem.getHeight() / 2, i);
+        }
+        timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
+        loggingInfo[0] = "Duration taken to get Video Thumbnails\t" +
+            timeTaken;
+
+        writeTimingInfo("testPerformanceThumbnailVideoItem (in mSec)", loggingInfo);
+    }
+
+    /**
+     * To test the performance of adding and removing the overlay to media item
+     *
+     * @throws Exception
+     */
+    // TODO : remove PRF_006
+    @LargeTest
+    public void testPerformanceOverlayVideoItem() throws Exception {
+        final String videoItemFileName1 = INPUT_FILE_PATH +
+            "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
+        final int videoItemStartTime1 = 0;
+        final int videoItemEndTime1 = 10000;
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String overlayFilename = INPUT_FILE_PATH
+            + "IMG_640x480_Overlay1.png";
+        final int overlayStartTime = 1000;
+        final int overlayDuration = 5000;
+
+        final String[] loggingInfo = new String[2];
+        MediaVideoItem mediaVideoItem = null;
+
+        try {
+            mediaVideoItem = new MediaVideoItem(mVideoEditor, "m0",
+                videoItemFileName1, renderingMode);
+            mediaVideoItem.setExtractBoundaries(videoItemStartTime1,
+                videoItemEndTime1);
+        } catch (Exception e1) {
+            assertTrue("Can not create Video Item with file name = "
+                + e1.toString(), false);
+        }
+        final OverlayFrame overlayFrame[] = new OverlayFrame[NUM_OF_ITERATIONS];
+        final Bitmap mBitmap =  mVideoEditorHelper.getBitmap(overlayFilename,
+            640, 480);
+        float timeTaken = 0.0f;
+        long beginTime = SystemClock.uptimeMillis();
+        for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
+            overlayFrame[i] = new OverlayFrame(mediaVideoItem, "overlay" + i,
+            mBitmap, overlayStartTime, overlayDuration);
+            mediaVideoItem.addOverlay(overlayFrame[i]);
+        }
+        timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
+        loggingInfo[0] = "Time taken to add & create Overlay\t" + timeTaken;
+
+        beginTime = SystemClock.uptimeMillis();
+        for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
+            assertEquals("Removing Overlays", overlayFrame[i],
+                mediaVideoItem.removeOverlay((overlayFrame[i].getId())));
+        }
+        timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
+        loggingInfo[1] = "\n\tTime taken to remove  Overlay\t" +
+            timeTaken;
+
+        writeTimingInfo("testPerformanceOverlayVideoItem (in mSec)", loggingInfo);
+    }
+
+    /**
+     * To test the performance of get properties of a Video media item
+     *
+     * @throws Exception
+     */
+    // TODO : remove PRF_007
+    @LargeTest
+    public void testPerformanceVideoItemProperties() throws Exception {
+        final String videoItemFileName1 = INPUT_FILE_PATH +
+            "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
+        final int videoItemStartTime1 = 0;
+        final int videoItemEndTime1 = 10100;
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final int aspectRatio = MediaProperties.ASPECT_RATIO_3_2;
+        final int fileType = MediaProperties.FILE_MP4;
+        final int videoCodecType = MediaProperties.VCODEC_H264BP;
+        final int duration = 77366;
+        final int videoBitrate = 3169971;
+        final int fps = 30;
+        final int videoProfile = MediaProperties.H264_PROFILE_0_LEVEL_1_3;
+        final int width = 1080;
+        final int height = MediaProperties.HEIGHT_720;
+        float timeTaken = 0.0f;
+        final String[] loggingInfo = new String[1];
+        final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
+            "m0", videoItemFileName1, renderingMode);
+        mediaVideoItem.setExtractBoundaries(videoItemStartTime1,
+            videoItemEndTime1);
+        long beginTime = SystemClock.uptimeMillis();
+        for (int i = 0; i < (NUM_OF_ITERATIONS*10); i++) {
+            try {
+                assertEquals("Aspect Ratio Mismatch",
+                    aspectRatio, mediaVideoItem.getAspectRatio());
+                assertEquals("File Type Mismatch",
+                    fileType, mediaVideoItem.getFileType());
+                assertEquals("VideoCodec Mismatch",
+                    videoCodecType, mediaVideoItem.getVideoType());
+                assertEquals("duration Mismatch",
+                    duration, mediaVideoItem.getDuration());
+                assertEquals("Video Profile ",
+                    videoProfile, mediaVideoItem.getVideoProfile());
+                assertEquals("Video height ",
+                    height, mediaVideoItem.getHeight());
+                assertEquals("Video width ",
+                    width, mediaVideoItem.getWidth());
+            } catch (Exception e1) {
+                assertTrue("Can not create Video Item with file name = "
+                    + e1.toString(), false);
+            }
+        }
+        timeTaken = calculateTimeTaken(beginTime, (NUM_OF_ITERATIONS*10));
+        loggingInfo[0] = "Time taken to get Media Properties\t"
+            + timeTaken;
+        writeTimingInfo("testPerformanceVideoItemProperties:", loggingInfo);
+    }
+
+    /**
+     * To test the performance of generatePreview : with Transitions
+     *
+     * @throws Exception
+     */
+    // TODO : remove PRF_008
+    @LargeTest
+    public void testPerformanceGeneratePreviewWithTransitions()
+        throws Exception {
+        final String videoItemFileName = INPUT_FILE_PATH +
+            "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
+        final String imageItemFileName = INPUT_FILE_PATH +
+            "IMG_1600x1200.jpg";
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final int transitionBehavior = Transition.BEHAVIOR_MIDDLE_FAST;
+        long averageTime = 0;
+        final String[] loggingInfo = new String[1];
+
+        final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
+            "mediaItem1", videoItemFileName, renderingMode);
+        mediaVideoItem.setExtractBoundaries(0, 10000);
+        mVideoEditor.addMediaItem(mediaVideoItem);
+
+        final MediaImageItem mediaImageItem = new MediaImageItem(mVideoEditor,
+            "mediaItem2", imageItemFileName, 10000, renderingMode);
+        mVideoEditor.addMediaItem(mediaImageItem);
+
+        final TransitionCrossfade transitionCrossFade = new TransitionCrossfade(
+            "transitionCrossFade", mediaVideoItem, mediaImageItem,
+            5000, transitionBehavior);
+        mVideoEditor.addTransition(transitionCrossFade);
+
+        for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
+            final long duration1 = SystemClock.uptimeMillis();
+            mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
+                public void onProgress(Object item, int action, int progress) {
+                }
+            });
+            final long duration2 = SystemClock.uptimeMillis();
+            mVideoEditor.removeTransition(transitionCrossFade.getId());
+            mVideoEditor.addTransition(transitionCrossFade);
+            averageTime += (duration2 - duration1);
+        }
+        final long durationToAddObjects = averageTime;
+        final float timeTaken = (float)durationToAddObjects *
+            1.0f/(float)NUM_OF_ITERATIONS;
+        loggingInfo[0] = "Time taken to Generate Preview with transition\t"
+            + timeTaken;
+        writeTimingInfo("testPerformanceGeneratePreviewWithTransitions:",
+            loggingInfo);
+    }
+
+    /**
+     * To test the performance of generatePreview : with KenBurn
+     *
+     * @throws Exception
+     */
+    // TODO : remove PRF_009
+    @LargeTest
+    public void testPerformanceWithKenBurn() throws Exception {
+        final String videoItemFileName = INPUT_FILE_PATH +
+            "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
+        final String imageItemFileName = INPUT_FILE_PATH +
+            "IMG_1600x1200.jpg";
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        long averageTime = 0;
+        final String[] loggingInfo = new String[1];
+        final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
+            "mediaItem1", videoItemFileName, renderingMode);
+        mediaVideoItem.setExtractBoundaries(0, 10000);
+        mVideoEditor.addMediaItem(mediaVideoItem);
+
+        final MediaImageItem mediaImageItem = new MediaImageItem(mVideoEditor,
+            "mediaItem2", imageItemFileName, 10000, renderingMode);
+        mVideoEditor.addMediaItem(mediaImageItem);
+
+        final Rect startRect = new Rect((mediaImageItem.getHeight() / 3),
+            (mediaImageItem.getWidth() / 3), (mediaImageItem.getHeight() / 2),
+            (mediaImageItem.getWidth() / 2));
+        final Rect endRect = new Rect(0, 0, mediaImageItem.getWidth(),
+            mediaImageItem.getHeight());
+        final EffectKenBurns kbEffectOnMediaItem =
+            new EffectKenBurns(mediaImageItem, "KBOnM2", startRect, endRect,
+                500, 3000);
+        mediaImageItem.addEffect(kbEffectOnMediaItem);
+
+        for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
+            final long duration1 = SystemClock.uptimeMillis();
+            mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
+                public void onProgress(Object item, int action, int progress) {
+                }
+            });
+            final long duration2 = SystemClock.uptimeMillis();
+            mediaImageItem.removeEffect(kbEffectOnMediaItem.getId());
+            mediaImageItem.addEffect(kbEffectOnMediaItem);
+            averageTime += duration2 - duration1;
+        }
+
+        final long durationToAddObjects = (averageTime);
+        final float timeTaken = (float)durationToAddObjects *
+            1.0f/(float)NUM_OF_ITERATIONS;
+        loggingInfo[0] = "Time taken to Generate KenBurn Effect \t"
+            + timeTaken;
+        writeTimingInfo("testPerformanceWithKenBurn", loggingInfo);
+    }
+
+    /**
+     * To test the performance of generatePreview : with Transitions and
+     * Effect,Overlapping scenario
+     *
+     * @throws Exception
+     */
+    // TODO : remove PRF_010
+    @LargeTest
+    public void testPerformanceEffectOverlappingTransition() throws Exception {
+        final String videoItemFileName1 = INPUT_FILE_PATH +
+            "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
+        final String videoItemFileName2 = INPUT_FILE_PATH
+            + "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
+        final int videoStartTime1 = 0;
+        final int videoEndTime1 = 10000;
+        final int videoStartTime2 = 0;
+        final int videoEndTime2 = 10000;
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final int transitionDuration = 5000;
+        final int transitionBehavior = Transition.BEHAVIOR_MIDDLE_FAST;
+        final int effectItemStartTime = 5000;
+        final int effectItemDurationTime = 5000;
+        final int effectType = EffectColor.TYPE_COLOR;
+        final int effectColorType = EffectColor.GREEN;
+        long averageDuration = 0;
+
+        final String[] loggingInfo = new String[1];
+        final MediaVideoItem mediaVideoItem1 = new MediaVideoItem(mVideoEditor,
+            "mediaItem1", videoItemFileName1, renderingMode);
+        mediaVideoItem1.setExtractBoundaries(videoStartTime1, videoEndTime1);
+        mVideoEditor.addMediaItem(mediaVideoItem1);
+
+        final MediaVideoItem mediaVideoItem2 = new MediaVideoItem(mVideoEditor,
+            "mediaItem2", videoItemFileName2, renderingMode);
+        mediaVideoItem2.setExtractBoundaries(videoStartTime2, videoEndTime2);
+        mVideoEditor.addMediaItem(mediaVideoItem2);
+
+        final TransitionCrossfade transitionCrossFade = new TransitionCrossfade(
+            "transitionCrossFade", mediaVideoItem1, mediaVideoItem2,
+            transitionDuration, transitionBehavior);
+        mVideoEditor.addTransition(transitionCrossFade);
+
+        final EffectColor effectColor = new EffectColor(mediaVideoItem1,
+            "effect", effectItemStartTime, effectItemDurationTime, effectType,
+             effectColorType);
+        mediaVideoItem1.addEffect(effectColor);
+
+        for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
+            final long duration1 = SystemClock.uptimeMillis();
+            mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
+                public void onProgress(Object item, int action, int progress) {
+                }
+            });
+            final long duration2 = SystemClock.uptimeMillis();
+            mVideoEditor.removeTransition(transitionCrossFade.getId());
+            mVideoEditor.addTransition(transitionCrossFade);
+            averageDuration += (duration2 - duration1);
+        }
+        SystemClock.uptimeMillis();
+        final long durationToAddObjects = (averageDuration);
+        final float timeTaken = (float)durationToAddObjects *
+            1.0f/(float)NUM_OF_ITERATIONS;
+        loggingInfo[0] =
+            "Time taken to testPerformanceEffectOverlappingTransition\t"
+            + timeTaken;
+        writeTimingInfo("testPerformanceEffectOverlappingTransition:",
+            loggingInfo);
+    }
+
+    /**
+     * To test creation of story board with Transition and Two Effects, Effect
+     * overlapping transitions
+     *
+     * @throws Exception
+     */
+    // TODO : remove PRF_011
+    @LargeTest
+    public void testPerformanceTransitionWithEffectOverlapping() throws Exception {
+        final String videoItemFileName1 = INPUT_FILE_PATH +
+            "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
+        final String videoItemFileName2 = INPUT_FILE_PATH
+            + "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final int transitionDuration = 5000;
+        final int transitionBehavior = Transition.BEHAVIOR_MIDDLE_FAST;
+        final int effectItemStartTime1 = 5000;
+        final int effectItemDurationTime1 = 5000;
+        final int effectType1 = EffectColor.TYPE_COLOR;
+        final int effectColorType1 = EffectColor.GREEN;
+        final int effectItemStartTime2 = 5000;
+        final int effectItemDurationTime2 = 5000;
+        final int effectType2 = EffectColor.TYPE_COLOR;
+        final int effectColorType2 = EffectColor.GREEN;
+        int averageTime = 0;
+        final String[] loggingInfo = new String[1];
+
+        final MediaVideoItem mediaVideoItem1 = new MediaVideoItem(mVideoEditor,
+            "mediaItem1", videoItemFileName1, renderingMode);
+        mVideoEditor.addMediaItem(mediaVideoItem1);
+
+        final MediaVideoItem mediaVideoItem2 = new MediaVideoItem(mVideoEditor,
+            "mediaItem2", videoItemFileName2, renderingMode);
+        mVideoEditor.addMediaItem(mediaVideoItem2);
+
+        final TransitionCrossfade transitionCrossFade = new TransitionCrossfade(
+            "transitionCrossFade", mediaVideoItem1, mediaVideoItem2,
+            transitionDuration, transitionBehavior);
+        mVideoEditor.addTransition(transitionCrossFade);
+
+        final EffectColor effectColor1 = new EffectColor(mediaVideoItem1,
+            "effect1", effectItemStartTime1, effectItemDurationTime1,
+            effectType1, effectColorType1);
+        mediaVideoItem1.addEffect(effectColor1);
+
+        final EffectColor effectColor2 = new EffectColor(mediaVideoItem2,
+            "effect2", effectItemStartTime2, effectItemDurationTime2,
+            effectType2, effectColorType2);
+        mediaVideoItem2.addEffect(effectColor2);
+
+        for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
+            final long duration1 = SystemClock.uptimeMillis();
+            mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
+                public void onProgress(Object item, int action, int progress) {
+                }
+            });
+            final long duration2 = SystemClock.uptimeMillis();
+            mVideoEditor.removeTransition(transitionCrossFade.getId());
+            mVideoEditor.addTransition(transitionCrossFade);
+            averageTime += duration2 - duration1;
+        }
+        final long durationToAddObjects = (averageTime);
+        final float timeTaken = (float)durationToAddObjects *
+            1.0f/(float)NUM_OF_ITERATIONS;
+        loggingInfo[0] = "Time taken to TransitionWithEffectOverlapping\t"
+            + timeTaken;
+        writeTimingInfo("testPerformanceTransitionWithEffectOverlapping",
+            loggingInfo);
+    }
+
+    /**
+     *To test ThumbnailList for H264
+     */
+    // TODO : TC_PRF_12
+    @LargeTest
+    public void testThumbnailH264NonIFrame() throws Exception {
+        final String videoItemFilename = INPUT_FILE_PATH +
+            "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
+        final int outWidth = 1080;
+        final int outHeight = 720;
+        final int atTime = 2400;
+        long durationToAddObjects = 0;
+        int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String[] loggingInfo = new String[1];
+        final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
+            "m1", videoItemFilename, renderingMode);
+        assertNotNull("MediaVideoItem", mediaVideoItem);
+
+        for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
+            final long duration1 = SystemClock.uptimeMillis();
+            mediaVideoItem.getThumbnail(outWidth, outHeight, atTime + i);
+            final long duration2 = SystemClock.uptimeMillis();
+            durationToAddObjects += (duration2 - duration1);
+        }
+        final float timeTaken = (float)durationToAddObjects *
+            1.0f/(float)NUM_OF_ITERATIONS;
+        loggingInfo[0] = "Time taken for Thumbnail generation \t"
+            + timeTaken;
+        writeTimingInfo("testThumbnailH264NonIFrame", loggingInfo);
+    }
+
+    /**
+     *To test ThumbnailList for H264
+     */
+    // TODO : TC_PRF_13
+    @LargeTest
+    public void testThumbnailH264AnIFrame() throws Exception {
+        final String videoItemFilename = INPUT_FILE_PATH +
+            "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
+        final int outWidth = 1080;
+        final int outHeight = 720;
+        final int atTime = 3000;
+        int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String[] loggingInfo = new String[1];
+        long durationToAddObjects = 0;
+
+        final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
+            "m1", videoItemFilename, renderingMode);
+        assertNotNull("MediaVideoItem", mediaVideoItem);
+
+        for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
+            final long duration1 = SystemClock.uptimeMillis();
+            mediaVideoItem.getThumbnail(outWidth, outHeight, atTime + i);
+            final long duration2 = SystemClock.uptimeMillis();
+            durationToAddObjects += (duration2 - duration1);
+        }
+        final float timeTaken = (float)durationToAddObjects *
+            1.0f/(float)NUM_OF_ITERATIONS;
+        loggingInfo[0] = "Time taken Thumbnail generation \t"
+            + timeTaken;
+        writeTimingInfo("testThumbnailH264AnIFrame", loggingInfo);
+    }
+
+    /**
+     * To test the performance : With an audio track
+     *
+     * @throws Exception
+     */
+    // TODO : remove PRF_014
+    @LargeTest
+    public void testPerformanceWithAudioTrack() throws Exception {
+        final String videoItemFileName1 = INPUT_FILE_PATH +
+            "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
+        final String audioFilename1 = INPUT_FILE_PATH +
+            "AACLC_44.1kHz_256kbps_s_1_17.mp4";
+        final String audioFilename2 = INPUT_FILE_PATH +
+            "AMRNB_8KHz_12.2Kbps_m_1_17.3gp";
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final int audioVolume = 50;
+        final String[] loggingInfo = new String[2];
+        float timeTaken = 0.0f;
+
+        final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
+            "mediaItem1", videoItemFileName1, renderingMode);
+        mVideoEditor.addMediaItem(mediaVideoItem);
+
+        final AudioTrack audioTrack1 = new AudioTrack(mVideoEditor,
+            "Audio Track1", audioFilename1);
+        audioTrack1.disableDucking();
+        audioTrack1.setVolume(audioVolume);
+        mVideoEditor.addAudioTrack(audioTrack1);
+
+        long beginTime = SystemClock.uptimeMillis();
+        mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
+            public void onProgress(Object item, int action, int progress) {
+            }
+        });
+        timeTaken = calculateTimeTaken(beginTime, 1);
+        loggingInfo[0] = "Time taken for 1st Audio Track (AACLC)\t"
+            + timeTaken;
+
+        final AudioTrack audioTrack2 = new AudioTrack(mVideoEditor,
+            "Audio Track2", audioFilename2);
+        audioTrack2.enableLoop();
+
+        beginTime = SystemClock.uptimeMillis();
+        mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
+            public void onProgress(Object item, int action, int progress) {
+            }
+        });
+        timeTaken = calculateTimeTaken(beginTime, 1);
+        loggingInfo[1] = "\n\tTime taken for 2nd Audio Track(AMRNB)\t"
+            + timeTaken;
+
+        writeTimingInfo("testPerformanceWithAudioTrack", loggingInfo);
+    }
+
+    /**
+     * To test the performance of adding and removing the
+     * image media item with 640 x 480
+     *
+     * @throws Exception
+     */
+    // TODO : remove PRF_015
+    @LargeTest
+    public void testPerformanceAddRemoveImageItem640x480() throws Exception {
+        final String imageItemFileName = INPUT_FILE_PATH + "IMG_640x480.jpg";
+        final int imageItemDuration = 0;
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String[] loggingInfo = new String[3];
+
+        float timeTaken = 0.0f;
+
+        final MediaImageItem[] mediaImageItem =
+            new MediaImageItem[NUM_OF_ITERATIONS];
+        long beginTime = SystemClock.uptimeMillis();
+        createImageItems(mediaImageItem, imageItemFileName, renderingMode,
+            imageItemDuration);
+        timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
+        loggingInfo[0] = "Time taken to Create  Media Image Item (640x480)\t"
+            + timeTaken;
+
+        beginTime = SystemClock.uptimeMillis();
+        addImageItems(mediaImageItem);
+        timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
+        loggingInfo[1] = "\n\tTime taken to add  Media Image Item (640x480)\t"
+            + timeTaken;
+
+        beginTime = SystemClock.uptimeMillis();
+        removeImageItems(mediaImageItem);
+        timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
+        loggingInfo[2] = "\n\tTime taken to remove  Media Image Item (640x480)\t"
+            + timeTaken;
+        writeTimingInfo("testPerformanceAddRemoveImageItem640x480 (in mSec)", loggingInfo);
+    }
+
+
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/VideoEditorStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/VideoEditorStressTest.java
new file mode 100755
index 0000000..0e70dd3
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/VideoEditorStressTest.java
@@ -0,0 +1,1317 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mediaframeworktest.stress;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.Writer;
+import java.util.List;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.media.videoeditor.AudioTrack;
+import android.media.videoeditor.EffectColor;
+import android.media.videoeditor.EffectKenBurns;
+import android.media.videoeditor.MediaImageItem;
+import android.media.videoeditor.MediaItem;
+import android.media.videoeditor.MediaProperties;
+import android.media.videoeditor.MediaVideoItem;
+import android.media.videoeditor.OverlayFrame;
+import android.media.videoeditor.Transition;
+import android.media.videoeditor.TransitionCrossfade;
+import android.media.videoeditor.TransitionAlpha;
+import android.media.videoeditor.TransitionFadeBlack;
+import android.media.videoeditor.TransitionSliding;
+import android.media.videoeditor.VideoEditor;
+import android.os.Environment;
+import android.test.ActivityInstrumentationTestCase;
+import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener;
+import android.os.Environment;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase;
+import android.media.videoeditor.VideoEditor.ExportProgressListener;
+import android.media.videoeditor.VideoEditorFactory;
+import android.media.videoeditor.ExtractAudioWaveformProgressListener;
+
+import android.os.Debug;
+import android.util.Log;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import com.android.mediaframeworktest.VideoEditorHelper;
+
+/**
+ * Junit / Instrumentation - performance measurement for media player and
+ * recorder
+ */
+public class VideoEditorStressTest
+        extends ActivityInstrumentationTestCase<MediaFrameworkTest> {
+
+    private final String TAG = "VideoEditorPerformance";
+
+    private final String PROJECT_LOCATION = VideoEditorHelper.PROJECT_LOCATION_COMMON;
+
+    private final String INPUT_FILE_PATH = VideoEditorHelper.INPUT_FILE_PATH_COMMON;
+
+    private final String VIDEOEDITOR_OUTPUT = PROJECT_LOCATION +
+        "VideoEditorStressMemOutput.txt";
+
+    private long BeginJavaMemory;
+    private long AfterJavaMemory;
+
+    private long BeginNativeMemory;
+    private long AfterNativeMemory;
+
+    public VideoEditorStressTest() {
+        super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+        new File(VIDEOEDITOR_OUTPUT).delete();
+    }
+
+    private final String PROJECT_CLASS_NAME =
+        "android.media.videoeditor.VideoEditorImpl";
+    private VideoEditor mVideoEditor;
+    private VideoEditorHelper mVideoEditorHelper;
+
+    @Override
+    protected void setUp() throws Exception {
+        // setup for each test case.
+        super.setUp();
+        mVideoEditorHelper = new VideoEditorHelper();
+        // Create a random String which will be used as project path, where all
+        // project related files will be stored.
+        final String projectPath =
+            mVideoEditorHelper.createRandomFile(PROJECT_LOCATION);
+        mVideoEditor = mVideoEditorHelper.createVideoEditor(projectPath);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mVideoEditorHelper.destroyVideoEditor(mVideoEditor);
+        // Clean the directory created as project path
+        mVideoEditorHelper.deleteProject(new File(mVideoEditor.getPath()));
+        System.gc();
+        super.tearDown();
+    }
+
+    private void writeTimingInfo(String[] information)
+        throws Exception {
+        File outFile = new File(VIDEOEDITOR_OUTPUT);
+        Writer output = new BufferedWriter(new FileWriter(outFile, true));
+        for (int i = 0; i < information.length; i++) {
+            output.write(information[i]);
+        }
+        output.close();
+    }
+
+    private void writeTestCaseHeader(String testCaseName)
+        throws Exception {
+        File outFile = new File(VIDEOEDITOR_OUTPUT);
+        Writer output = new BufferedWriter(new FileWriter(outFile, true));
+        output.write("\n\n" + testCaseName + "\n");
+        output.close();
+    }
+
+    private void getBeginMemory() throws Exception {
+        System.gc();
+        Thread.sleep(2500);
+        BeginNativeMemory = Debug.getNativeHeapAllocatedSize();
+    }
+    private void getAfterMemory_updateLog(String[] loggingInfo, boolean when,
+        int iteration)
+        throws Exception {
+        System.gc();
+        Thread.sleep(2500);
+        AfterNativeMemory = Debug.getNativeHeapAllocatedSize();
+        if(when == false){
+            loggingInfo[0] = "\n Before Remove: iteration No.= " + iteration +
+                "\t " + (AfterNativeMemory - BeginNativeMemory);
+        } else {
+            loggingInfo[0] = "\n After Remove: iteration No.= " + iteration +
+                "\t " + (AfterNativeMemory - BeginNativeMemory);
+        }
+        writeTimingInfo(loggingInfo);
+    }
+
+    /**
+     * To stress test MediaItem(Video Item) adding functionality
+     *
+     * @throws Exception
+     */
+    // TODO : remove TC_STR_001
+    @LargeTest
+    public void testStressAddRemoveVideoItem() throws Exception {
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+
+        final String videoItemFileName1 = INPUT_FILE_PATH +
+            "H264_BP_176x144_15fps_144kbps_AMRNB_8kHz_12.2kbps_m_1_17.3gp";
+        final String videoItemFileName2 = INPUT_FILE_PATH +
+            "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_96kbps_s_0_21.mp4";
+        final String videoItemFileName3 = INPUT_FILE_PATH +
+            "H263_profile0_176x144_15fps_128kbps_1_35.3gp";
+        final String videoItemFileName4 = INPUT_FILE_PATH +
+            "MPEG4_SP_640x480_15fps_1200kbps_AACLC_48khz_64kbps_m_1_17.3gp";
+        final String[] loggingInfo = new String[1];
+        writeTestCaseHeader("testStressAddRemoveVideoItem");
+        int i = 0;
+        getBeginMemory();
+
+        for ( i = 0; i < 50; i++) {
+            if (i % 4 == 0) {
+                final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
+                    "m1" + i, videoItemFileName1, renderingMode);
+                mediaItem1.setExtractBoundaries(0, 5000);
+                mVideoEditor.addMediaItem(mediaItem1);
+            }
+            if (i % 4 == 1) {
+                final MediaVideoItem mediaItem2 = new MediaVideoItem(mVideoEditor,
+                    "m2" + i, videoItemFileName2, renderingMode);
+                mediaItem2.setExtractBoundaries(0, 10000);
+                mVideoEditor.addMediaItem(mediaItem2);
+            }
+            if (i % 4 == 2) {
+                final MediaVideoItem mediaItem3 = new MediaVideoItem(mVideoEditor,
+                    "m3" + i, videoItemFileName3, renderingMode);
+                mediaItem3.setExtractBoundaries(30000, 45000);
+                mVideoEditor.addMediaItem(mediaItem3);
+            }
+            if (i % 4 == 3) {
+                final MediaVideoItem mediaItem4 = new MediaVideoItem(mVideoEditor,
+                    "m4" + i, videoItemFileName4, renderingMode);
+                mediaItem4.setExtractBoundaries(10000, 30000);
+                mVideoEditor.addMediaItem(mediaItem4);
+            }
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, false, i);
+            }
+        }
+        getAfterMemory_updateLog(loggingInfo, false, i);
+
+        /** Remove items and check for memory leak if any */
+        getBeginMemory();
+        for ( i = 0; i < 50; i++) {
+            if (i % 4 == 0) {
+                mVideoEditor.removeMediaItem("m1" + i);
+            }
+            if (i % 4 == 1) {
+                mVideoEditor.removeMediaItem("m2" + i);
+            }
+            if (i % 4 == 2) {
+                mVideoEditor.removeMediaItem("m3" + i);
+            }
+            if (i % 4 == 3) {
+                mVideoEditor.removeMediaItem("m4" + i);
+            }
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, true, i);
+            }
+        }
+        getAfterMemory_updateLog(loggingInfo, true, i);
+    }
+
+    /**
+     * To stress test MediaItem(Image Item) adding functionality
+     *
+     * @throws Exception
+     */
+    // TODO : remove TC_STR_002
+    @LargeTest
+    public void testStressAddRemoveImageItem() throws Exception {
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String ImageItemFileName1 = INPUT_FILE_PATH +
+            "IMG_1600x1200.jpg";
+        final String ImageItemFileName2 = INPUT_FILE_PATH +
+            "IMG_640x480.jpg";
+        final String ImageItemFileName3 = INPUT_FILE_PATH +
+            "IMG_320x240.jpg";
+        final String ImageItemFileName4 = INPUT_FILE_PATH +
+            "IMG_176x144.jpg";
+        final String[] loggingInfo = new String[1];
+        int i = 0;
+        writeTestCaseHeader("testStressAddRemoveImageItem");
+        getBeginMemory();
+        for ( i = 0; i < 50; i++) {
+            if (i % 4 == 0) {
+                final MediaImageItem mediaItem1 = new MediaImageItem(mVideoEditor,
+                    "m1"+ i, ImageItemFileName1, 5000, renderingMode);
+                mVideoEditor.addMediaItem(mediaItem1);
+            }
+            if (i % 4 == 1) {
+                final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
+                    "m2"+ i, ImageItemFileName2, 10000, renderingMode);
+                mVideoEditor.addMediaItem(mediaItem2);
+            }
+            if (i % 4 == 2) {
+                final MediaImageItem mediaItem3 = new MediaImageItem(mVideoEditor,
+                    "m3"+ i, ImageItemFileName3, 15000, renderingMode);
+                mVideoEditor.addMediaItem(mediaItem3);
+            }
+            if (i % 4 == 3) {
+                final MediaImageItem mediaItem4 = new MediaImageItem(mVideoEditor,
+                    "m4"+ i, ImageItemFileName4, 20000, renderingMode);
+                mVideoEditor.addMediaItem(mediaItem4);
+            }
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, false, i);
+            }
+        }
+        getAfterMemory_updateLog(loggingInfo, false, i);
+
+        /** Remove items and check for memory leak if any */
+        getBeginMemory();
+        for ( i = 0; i < 50; i++) {
+            if (i % 4 == 0) {
+                mVideoEditor.removeMediaItem("m1"+i);
+            }
+            if (i % 4 == 1) {
+                mVideoEditor.removeMediaItem("m2"+i);
+            }
+            if (i % 4 == 2) {
+                mVideoEditor.removeMediaItem("m3"+i);
+            }
+            if (i % 4 == 3) {
+                mVideoEditor.removeMediaItem("m4"+i);
+            }
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, true, i);
+            }
+        }
+        getAfterMemory_updateLog(loggingInfo, true, i);
+    }
+
+    /**
+     * To stress test transition
+     *
+     * @throws Exception
+     */
+    // TODO : remove TC_STR_003
+    @LargeTest
+    public void testStressAddRemoveTransition() throws Exception {
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String VideoItemFileName1 = INPUT_FILE_PATH +
+            "H264_BP_800x480_15fps_512kbps_1_17.mp4";
+        final String ImageItemFileName2 = INPUT_FILE_PATH +
+            "IMG_1600x1200.jpg";
+        final String VideoItemFileName3 = INPUT_FILE_PATH +
+            "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
+        final String maskFilename = INPUT_FILE_PATH +
+            "TransitionSpiral_QVGA.jpg";
+        final String[] loggingInfo = new String[1];
+        int i = 0;
+        writeTestCaseHeader("testStressAddRemoveTransition");
+        getBeginMemory();
+        for ( i = 0; i < 50; i++) {
+            if (i % 4 == 0) {
+                final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
+                    "m1"+i, VideoItemFileName1, renderingMode);
+                mVideoEditor.addMediaItem(mediaItem1);
+                mediaItem1.setExtractBoundaries(0, 10000);
+                final TransitionCrossfade tranCrossfade =
+                    new TransitionCrossfade("transCF" + i, null,
+                        mediaItem1, 5000, Transition.BEHAVIOR_MIDDLE_FAST);
+                mVideoEditor.addTransition(tranCrossfade);
+            }
+            if (i % 4 == 1) {
+                final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
+                    "m1"+i, VideoItemFileName1, renderingMode);
+                mVideoEditor.addMediaItem(mediaItem1);
+                mediaItem1.setExtractBoundaries(0, 10000);
+
+                final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
+                    "m2" +i, ImageItemFileName2, 10000, renderingMode);
+                mVideoEditor.addMediaItem(mediaItem2);
+
+                final TransitionAlpha transitionAlpha =
+                    mVideoEditorHelper.createTAlpha("transAlpha" + i, mediaItem1,
+                        mediaItem2, 5000, Transition.BEHAVIOR_SPEED_UP,
+                        maskFilename, 10, false);
+                transitionAlpha.setDuration(4000);
+                mVideoEditor.addTransition(transitionAlpha);
+            }
+            if (i % 4 == 2) {
+                final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
+                    "m2" + i, ImageItemFileName2, 10000, renderingMode);
+                mVideoEditor.addMediaItem(mediaItem2);
+
+                final MediaVideoItem mediaItem3 = new MediaVideoItem(mVideoEditor,
+                    "m3" + i, VideoItemFileName3, renderingMode);
+                mVideoEditor.addMediaItem(mediaItem3);
+
+                mediaItem3.setExtractBoundaries(0, 10000);
+                final TransitionAlpha transitionAlpha =
+                    mVideoEditorHelper.createTAlpha("transAlpha" + i, mediaItem2,
+                        mediaItem3, 5000, Transition.BEHAVIOR_SPEED_UP,
+                        maskFilename, 10, false);
+                transitionAlpha.setDuration(4000);
+                mVideoEditor.addTransition(transitionAlpha);
+
+                mediaItem3.setExtractBoundaries(0, 6000);
+
+                final TransitionSliding transition2And3 =
+                    mVideoEditorHelper.createTSliding("transSlide" +i, mediaItem2,
+                        mediaItem3, 3000, Transition.BEHAVIOR_MIDDLE_FAST,
+                        TransitionSliding.DIRECTION_LEFT_OUT_RIGHT_IN);
+                mVideoEditor.addTransition(transition2And3);
+            }
+            if (i % 4 == 3) {
+                final MediaVideoItem mediaItem3 = new MediaVideoItem(mVideoEditor,
+                    "m3" + i, VideoItemFileName3, renderingMode);
+                mVideoEditor.addMediaItem(mediaItem3);
+                mediaItem3.setExtractBoundaries(0, 5000);
+
+                final TransitionFadeBlack transition3 =
+                    mVideoEditorHelper.createTFadeBlack("transFB" +i, mediaItem3,
+                        null, 2500, Transition.BEHAVIOR_SPEED_UP);
+                transition3.setDuration(500);
+                mVideoEditor.addTransition(transition3);
+            }
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, false, i);
+            }
+        }
+        getAfterMemory_updateLog(loggingInfo, false, i);
+
+        /** Remove items and check for memory leak if any */
+        getBeginMemory();
+        for ( i = 0; i < 50; i++) {
+            if (i % 4 == 0) {
+                mVideoEditor.removeTransition("transCF" + i);
+                mVideoEditor.removeMediaItem("m1" + i);
+            }
+            if (i % 4 == 1) {
+                mVideoEditor.removeTransition("transAlpha" + i);
+                mVideoEditor.removeMediaItem("m1" + i);
+                mVideoEditor.removeMediaItem("m2" + i);
+            }
+            if (i % 4 == 2) {
+                mVideoEditor.removeTransition("transSlide" +i);
+                mVideoEditor.removeMediaItem("m2" + i);
+                mVideoEditor.removeMediaItem("m3" + i);
+            }
+            if (i % 4 == 3) {
+                mVideoEditor.removeMediaItem("m3" + i);
+            }
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, true, i);
+            }
+        }
+        getAfterMemory_updateLog(loggingInfo, true, i);
+    }
+
+    /**
+     * To stress test overlay
+     *
+     * @throws Exception
+     */
+    // TODO : remove TC_STR_004
+    @LargeTest
+    public void testStressAddRemoveOverlay() throws Exception {
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String VideoItemFileName1 = INPUT_FILE_PATH +
+            "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
+        final String ImageItemFileName2 = INPUT_FILE_PATH +
+            "IMG_640x480.jpg";
+        final String OverlayFile3 = INPUT_FILE_PATH +
+            "IMG_640x480_Overlay1.png";
+        final String OverlayFile4 = INPUT_FILE_PATH +
+            "IMG_640x480_Overlay2.png";
+        final String[] loggingInfo = new String[1];
+        int i = 0;
+        final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
+            "m1", VideoItemFileName1, renderingMode);
+        mVideoEditor.addMediaItem(mediaItem1);
+
+        final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
+            "m2", ImageItemFileName2, 10000, renderingMode);
+        mVideoEditor.addMediaItem(mediaItem2);
+        writeTestCaseHeader("testStressAddRemoveOverlay");
+        getBeginMemory();
+        for ( i = 0; i < 50; i++) {
+            if (i % 3 == 0) {
+                mediaItem1.setExtractBoundaries(0, 10000);
+                final Bitmap mBitmap =  mVideoEditorHelper.getBitmap(
+                    OverlayFile3, 640, 480);
+                final OverlayFrame overlayFrame =
+                    mVideoEditorHelper.createOverlay(mediaItem1, "overlay" + i,
+                        mBitmap, 1000, 5000);
+                mediaItem1.addOverlay(overlayFrame);
+                mediaItem1.removeOverlay("overlay"+i);
+            }
+            if (i % 3 == 1) {
+                final Bitmap mBitmap =  mVideoEditorHelper.getBitmap(
+                    OverlayFile4, 640, 480);
+                final OverlayFrame overlayFrame =
+                    mVideoEditorHelper.createOverlay(mediaItem2, "overlay" + i,
+                        mBitmap, 1000, 5000);
+                mediaItem2.addOverlay(overlayFrame);
+                mediaItem2.removeOverlay("overlay"+i);
+            }
+            if (i % 3 == 2) {
+                mediaItem1.setExtractBoundaries(0, 10000);
+                final Bitmap mBitmap =  mVideoEditorHelper.getBitmap(
+                    OverlayFile4, 640, 480);
+                final OverlayFrame overlayFrame =
+                    mVideoEditorHelper.createOverlay(mediaItem1, "overlay" + i,
+                        mBitmap, 0, mediaItem1.getDuration());
+                mediaItem1.addOverlay(overlayFrame);
+                mediaItem1.removeOverlay("overlay"+i);
+            }
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, false, i);
+            }
+        }
+        getAfterMemory_updateLog(loggingInfo, false, i);
+    }
+
+    /**
+     * To stress test Effects
+     *
+     * @throws Exception
+     */
+    // TODO : remove TC_STR_005
+    @LargeTest
+    public void testStressAddRemoveEffects() throws Exception {
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String VideoItemFileName1 = INPUT_FILE_PATH +
+            "MPEG4_SP_640x480_15fps_1200kbps_AACLC_48khz_64kbps_m_1_17.3gp";
+        final String ImageItemFileName2 = INPUT_FILE_PATH +
+            "IMG_1600x1200.jpg";
+        final String[] loggingInfo = new String[1];
+        final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
+            "m1", VideoItemFileName1, renderingMode);
+        mVideoEditor.addMediaItem(mediaItem1);
+        final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
+            "m2", ImageItemFileName2, 10000, renderingMode);
+        int i = 0;
+        mVideoEditor.addMediaItem(mediaItem2);
+        writeTestCaseHeader("testStressAddRemoveEffects");
+        getBeginMemory();
+        for ( i = 0; i < 50; i++) {
+            if (i % 5 == 0) {
+                mediaItem1.setExtractBoundaries(10000, 30000);
+                final EffectColor effectColor1 =
+                    mVideoEditorHelper.createEffectItem(mediaItem1, "effect1"+i,
+                        10000, (mediaItem1.getTimelineDuration()-1000),
+                        EffectColor.TYPE_COLOR, EffectColor.GREEN);
+                mediaItem1.addEffect(effectColor1);
+            }
+            if (i % 5 == 1) {
+                mediaItem2.setDuration(20000);
+                final EffectColor effectColor1 =
+                    mVideoEditorHelper.createEffectItem(mediaItem2, "effect1"+i,
+                        0, 4000, EffectColor.TYPE_GRADIENT, EffectColor.GRAY);
+                mediaItem2.addEffect(effectColor1);
+            }
+            if (i % 5 == 2) {
+                mediaItem1.setExtractBoundaries(10000, 30000);
+                final EffectColor effectColor1 =
+                    mVideoEditorHelper.createEffectItem(mediaItem1, "effect1"+i,
+                        (mediaItem1.getTimelineDuration() - 4000), 4000,
+                        EffectColor.TYPE_SEPIA, 0);
+                mediaItem1.addEffect(effectColor1);
+            }
+            if (i % 5 == 3) {
+                mediaItem2.setDuration(20000);
+                final EffectColor effectColor1 =
+                    mVideoEditorHelper.createEffectItem(mediaItem2, "effect1"+i,
+                        10000, 4000, EffectColor.TYPE_NEGATIVE, 0);
+                mediaItem2.addEffect(effectColor1);
+            }
+            if (i % 5 == 4) {
+                mediaItem2.setDuration(20000);
+                final Rect startRect = new Rect((mediaItem2.getHeight() / 3),
+                    (mediaItem2.getWidth() / 3), (mediaItem2.getHeight() / 2),
+                    (mediaItem2.getWidth() / 2));
+                final Rect endRect = new Rect(0, 0, mediaItem2.getWidth(),
+                    mediaItem2.getHeight());
+                final EffectKenBurns kbEffectOnMediaItem = new EffectKenBurns(
+                    mediaItem2, "KBOnM2" + i, startRect, endRect, 500,
+                    (mediaItem2.getDuration() - 500));
+                mediaItem2.addEffect(kbEffectOnMediaItem);
+            }
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, false, i);
+            }
+        }
+        getAfterMemory_updateLog(loggingInfo, false, i);
+
+        /** Remove items and check for memory leak if any */
+        getBeginMemory();
+        for ( i = 0; i < 50; i++) {
+            if (i % 5 == 0) {
+                mediaItem1.removeEffect("effect1"+i);
+            }
+            if (i % 5 == 1) {
+                mediaItem1.removeEffect("effect1"+i);
+            }
+            if (i % 5 == 2) {
+                mediaItem1.removeEffect("effect1"+i);
+            }
+            if (i % 5 == 3) {
+                mediaItem1.removeEffect("effect1"+i);
+            }
+            if (i % 5 == 4) {
+                mediaItem1.removeEffect("KBOnM2"+i);
+            }
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, true, i);
+            }
+        }
+        getAfterMemory_updateLog(loggingInfo, true, i);
+    }
+
+    /**
+     * This method will test thumbnail list extraction in a loop = 200 for Video
+     * Item
+     *
+     * @throws Exception
+     */
+    // TODO : remove TC_STR_006
+    @LargeTest
+    public void testStressThumbnailVideoItem() throws Exception {
+        final String videoItemFileName = INPUT_FILE_PATH
+                + "H264_BP_640x480_15fps_1200Kbps_AACLC_48KHz_64kps_m_0_27.3gp";
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String[] loggingInfo = new String[1];
+        int i = 0;
+        final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
+            "m1", videoItemFileName, renderingMode);
+        writeTestCaseHeader("testStressThumbnailVideoItem");
+        getBeginMemory();
+        for ( i = 0; i < 50; i++) {
+            if (i % 4 == 0) {
+                final Bitmap[] thumbNails =
+                    mediaVideoItem.getThumbnailList(mediaVideoItem.getWidth()*3,
+                        mediaVideoItem.getHeight()*2, i, 5000, 2);
+                // Recycle this Bitmap array
+                for (int i1 = 0; i1 < thumbNails.length; i1++) {
+                    thumbNails[i1].recycle();
+                }
+            }
+            if (i % 4 == 1) {
+                final Bitmap[] thumbNails =
+                    mediaVideoItem.getThumbnailList(mediaVideoItem.getWidth()/2,
+                        mediaVideoItem.getHeight() * 3, i, 5000, 2);
+                // Recycle this Bitmap array
+                for (int i1 = 0; i1 < thumbNails.length; i1++) {
+                    thumbNails[i1].recycle();
+                }
+            }
+            if (i % 4 == 2) {
+                final Bitmap[] thumbNails =
+                    mediaVideoItem.getThumbnailList(mediaVideoItem.getWidth()*2,
+                        mediaVideoItem.getHeight() / 3, i, 5000, 2);
+                // Recycle this Bitmap array
+                for (int i1 = 0; i1 < thumbNails.length; i1++) {
+                    thumbNails[i1].recycle();
+                }
+            }
+            if (i % 4 == 3) {
+                final Bitmap[] thumbNails =
+                    mediaVideoItem.getThumbnailList(mediaVideoItem.getWidth(),
+                        mediaVideoItem.getHeight(), i, 5000, 2);
+                // Recycle this Bitmap array
+                for (int i1 = 0; i1 < thumbNails.length; i1++) {
+                    thumbNails[i1].recycle();
+                }
+            }
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, false, i);
+            }
+        }
+        getAfterMemory_updateLog(loggingInfo, false, i);
+    }
+
+    /**
+     * To stress test media properties
+     *
+     * @throws Exception
+     */
+    // TODO : remove TC_STR_007
+    @LargeTest
+    public void testStressMediaProperties() throws Exception {
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String VideoItemFileName1 = INPUT_FILE_PATH +
+            "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
+        final String ImageItemFileName2 = INPUT_FILE_PATH +
+            "IMG_640x480.jpg";
+        final String AudioItemFileName3 = INPUT_FILE_PATH +
+            "AACLC_44.1kHz_256kbps_s_1_17.mp4";
+        final String[] loggingInfo = new String[1];
+        int i = 0;
+        final int videoAspectRatio = MediaProperties.ASPECT_RATIO_3_2;
+        final int videoFileType = MediaProperties.FILE_MP4;
+        final int videoCodecType = MediaProperties.VCODEC_H264BP;
+        final int videoDuration = 77366;
+        final int videoProfile = MediaProperties.H264_PROFILE_0_LEVEL_1_3;
+        final int videoHeight = MediaProperties.HEIGHT_720;
+        final int videoWidth = 1080;
+
+        final int imageAspectRatio = MediaProperties.ASPECT_RATIO_4_3;
+        final int imageFileType = MediaProperties.FILE_JPEG;
+        final int imageWidth = 640;
+        final int imageHeight = MediaProperties.HEIGHT_480;
+
+        final int audioDuration = 77554;
+        final int audioCodecType = MediaProperties.ACODEC_AAC_LC;
+        final int audioSamplingFrequency = 44100;
+        final int audioChannel = 2;
+        writeTestCaseHeader("testStressMediaProperties");
+        getBeginMemory();
+        for ( i = 0; i < 50; i++) {
+            if (i % 3 == 0) {
+                final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
+                    "m1" + i, VideoItemFileName1, renderingMode);
+                mVideoEditor.addMediaItem(mediaItem1);
+                mediaItem1.setExtractBoundaries(0, 20000);
+                assertEquals("Aspect Ratio Mismatch",
+                    videoAspectRatio, mediaItem1.getAspectRatio());
+                assertEquals("File Type Mismatch",
+                    videoFileType, mediaItem1.getFileType());
+                assertEquals("VideoCodec Mismatch",
+                    videoCodecType, mediaItem1.getVideoType());
+                assertEquals("duration Mismatch",
+                    videoDuration, mediaItem1.getDuration());
+                assertEquals("Video Profile ",
+                    videoProfile, mediaItem1.getVideoProfile());
+                assertEquals("Video height ",
+                    videoHeight, mediaItem1.getHeight());
+                assertEquals("Video width ",
+                    videoWidth, mediaItem1.getWidth());
+                mVideoEditor.removeMediaItem("m1" + i);
+            }
+            if (i % 3 == 1) {
+                final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
+                    "m2" + i, ImageItemFileName2, 10000, renderingMode);
+                mVideoEditor.addMediaItem(mediaItem2);
+                assertEquals("Aspect Ratio Mismatch",
+                    imageAspectRatio, mediaItem2.getAspectRatio());
+                assertEquals("File Type Mismatch",
+                    imageFileType, mediaItem2.getFileType());
+                assertEquals("Image height",
+                    imageHeight, mediaItem2.getHeight());
+                assertEquals("Image width",
+                    imageWidth, mediaItem2.getWidth());
+                mVideoEditor.removeMediaItem("m2" + i);
+            }
+            if (i % 3 == 2) {
+                final AudioTrack mediaItem3 = new AudioTrack(mVideoEditor,
+                    "m3" + i, AudioItemFileName3);
+                mVideoEditor.addAudioTrack(mediaItem3);
+                assertEquals("AudioType Mismatch", audioCodecType,
+                    mediaItem3.getAudioType());
+                assertEquals("Audio Sampling", audioSamplingFrequency,
+                    mediaItem3.getAudioSamplingFrequency());
+                assertEquals("Audio Channels",
+                    audioChannel, mediaItem3.getAudioChannels());
+                assertEquals("duration Mismatch", audioDuration,
+                    mediaItem3.getDuration());
+                mVideoEditor.removeAudioTrack("m3" + i);
+            }
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, false, i);
+            }
+        }
+        getAfterMemory_updateLog(loggingInfo, false, i);
+    }
+
+    /**
+     * To stress test insert and move of mediaitems
+     *
+     * @throws Exception
+     */
+    // TODO : remove TC_STR_008
+    @LargeTest
+    public void testStressInsertMovieItems() throws Exception {
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String VideoItemFileName1 = INPUT_FILE_PATH +
+            "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
+        final String VideoItemFileName2 = INPUT_FILE_PATH +
+            "H264_BP_800x480_15fps_512kbps_1_17.mp4";
+        final String VideoItemFileName3 = INPUT_FILE_PATH +
+            "MPEG4_SP_640x480_15fps_1200kbps_AACLC_48khz_64kbps_m_1_17.3gp";
+        final String[] loggingInfo = new String[1];
+        int i = 0;
+        writeTestCaseHeader("testStressInsertMoveItems");
+
+        final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
+            "m1", VideoItemFileName1, renderingMode);
+        mVideoEditor.addMediaItem(mediaItem1);
+        mediaItem1.setExtractBoundaries(0, 10000);
+
+        final MediaVideoItem mediaItem2 = new MediaVideoItem(mVideoEditor,
+            "m2", VideoItemFileName2, renderingMode);
+        mVideoEditor.addMediaItem(mediaItem2);
+        mediaItem2.setExtractBoundaries(0, 15000);
+
+        getBeginMemory();
+        for ( i = 0; i < 50; i++) {
+            final MediaVideoItem mediaItem3 = new MediaVideoItem(mVideoEditor,
+                "m3" + i, VideoItemFileName3, renderingMode);
+            mediaItem3.setExtractBoundaries(0, 15000);
+            mVideoEditor.insertMediaItem(mediaItem3, "m1");
+            mVideoEditor.moveMediaItem("m2", "m3" + i);
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, false, i);
+            }
+        }
+        getAfterMemory_updateLog(loggingInfo, false, i);
+
+        /** Remove items and check for memory leak if any */
+        getBeginMemory();
+        for ( i = 0; i < 50; i++) {
+            mVideoEditor.removeMediaItem("m3" + i);
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, true, i);
+            }
+        }
+            mVideoEditor.removeMediaItem("m2");
+            mVideoEditor.removeMediaItem("m1");
+        getAfterMemory_updateLog(loggingInfo, true, i);
+    }
+
+    /**
+     * To stress test : load and save
+     *
+     * @throws Exception
+     */
+    // TODO : remove TC_STR_009
+    @LargeTest
+    public void testStressLoadAndSave() throws Exception {
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String VideoItemFileName1 = INPUT_FILE_PATH +
+            "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
+        final String VideoItemFileName2 = INPUT_FILE_PATH +
+            "H264_BP_800x480_15fps_512kbps_1_17.mp4";
+        final String VideoItemFileName3 = INPUT_FILE_PATH +
+            "MPEG4_SP_640x480_15fps_1200kbps_AACLC_48khz_64kbps_m_1_17.3gp";
+        final String ImageItemFileName4 = INPUT_FILE_PATH +
+            "IMG_640x480.jpg";
+        final String ImageItemFileName5 = INPUT_FILE_PATH +
+            "IMG_176x144.jpg";
+        final String OverlayFile6 = INPUT_FILE_PATH +
+            "IMG_640x480_Overlay1.png";
+        final String[] loggingInfo = new String[1];
+        int i = 0;
+        final String[] projectPath = new String[10];
+        writeTestCaseHeader("testStressLoadAndSave");
+        getBeginMemory();
+        for( i=0; i < 10; i++){
+
+            projectPath[i] =
+                mVideoEditorHelper.createRandomFile(PROJECT_LOCATION);
+            final VideoEditor mVideoEditor1 =
+                mVideoEditorHelper.createVideoEditor(projectPath[i]);
+
+            final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor1,
+                "m1", VideoItemFileName1, renderingMode);
+            mVideoEditor1.addMediaItem(mediaItem1);
+            mediaItem1.setExtractBoundaries(0, 10000);
+
+            final MediaVideoItem mediaItem2 = new MediaVideoItem(mVideoEditor1,
+                "m2", VideoItemFileName2, renderingMode);
+            mVideoEditor1.addMediaItem(mediaItem2);
+            mediaItem2.setExtractBoundaries(mediaItem2.getDuration()/4,
+                mediaItem2.getDuration()/2);
+
+            final MediaVideoItem mediaItem3 = new MediaVideoItem(mVideoEditor1,
+                "m3", VideoItemFileName3, renderingMode);
+            mVideoEditor1.addMediaItem(mediaItem3);
+            mediaItem3.setExtractBoundaries(mediaItem3.getDuration()/2,
+                mediaItem3.getDuration());
+
+            final MediaImageItem mediaItem4 = new MediaImageItem(mVideoEditor1,
+                "m4", ImageItemFileName4, 5000, renderingMode);
+            mVideoEditor1.addMediaItem(mediaItem4);
+
+            final MediaImageItem mediaItem5 = new MediaImageItem(mVideoEditor1,
+                "m5", ImageItemFileName5, 5000, renderingMode);
+            mVideoEditor1.addMediaItem(mediaItem5);
+
+            final EffectColor effectColor1 =
+                mVideoEditorHelper.createEffectItem(mediaItem3, "effect1",
+                    10000, 2000, EffectColor.TYPE_COLOR, EffectColor.GREEN);
+            mediaItem3.addEffect(effectColor1);
+
+            final Bitmap mBitmap =  mVideoEditorHelper.getBitmap(OverlayFile6,
+                640, 480);
+            final OverlayFrame overlayFrame =
+                mVideoEditorHelper.createOverlay(mediaItem4, "overlay",
+                    mBitmap, 4000, 1000);
+            mediaItem4.addOverlay(overlayFrame);
+
+            final TransitionCrossfade tranCrossfade =
+                new TransitionCrossfade("transCF", mediaItem1,
+                    mediaItem2, 5000, Transition.BEHAVIOR_MIDDLE_FAST);
+            mVideoEditor1.addTransition(tranCrossfade);
+
+            final EffectColor effectColor2 =
+                mVideoEditorHelper.createEffectItem(mediaItem4, "effect2", 0,
+                    mediaItem4.getDuration(), EffectColor.TYPE_COLOR,
+                    EffectColor.PINK);
+            mediaItem4.addEffect(effectColor2);
+
+            mVideoEditor1.generatePreview(new MediaProcessingProgressListener() {
+                public void onProgress(Object item, int action, int progress) {
+                }
+            });
+
+            mVideoEditor1.save();
+            mVideoEditor1.release();
+
+            getAfterMemory_updateLog(loggingInfo, false, i);
+        }
+        getAfterMemory_updateLog(loggingInfo, false, i);
+
+        /** Remove items and check for memory leak if any */
+        getBeginMemory();
+        for( i=0; i<10; i++){
+            final VideoEditor mVideoEditor1b =
+                VideoEditorFactory.load(projectPath[i], true);
+            List<MediaItem> mediaList = mVideoEditor1b.getAllMediaItems();
+            assertEquals("Media Item List Size", 5, mediaList.size());
+
+            mediaList.get(3).removeEffect("effect1");
+            mediaList.get(3).removeEffect("effect2");
+            mediaList.get(2).removeOverlay("overlay");
+            mVideoEditor1b.removeTransition("transCF");
+            mVideoEditor1b.removeMediaItem("m5");
+            mVideoEditor1b.removeMediaItem("m4");
+            mVideoEditor1b.removeMediaItem("m3");
+            mVideoEditor1b.removeMediaItem("m2");
+            mVideoEditor1b.removeMediaItem("m1");
+            mVideoEditor1b.release();
+            getAfterMemory_updateLog(loggingInfo, true, i);
+        }
+        getAfterMemory_updateLog(loggingInfo, true, i);
+    }
+
+    /**
+     * To stress test : Multiple Export
+     *
+     * @throws Exception
+     */
+    // TODO : remove TC_STR_010
+    @LargeTest
+    public void testStressMultipleExport() throws Exception {
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String VideoItemFileName1 = INPUT_FILE_PATH +
+            "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
+        final String VideoItemFileName2 = INPUT_FILE_PATH +
+            "H264_BP_800x480_15fps_512kbps_1_17.mp4";
+        final String[] loggingInfo = new String[1];
+        final String outFilename = mVideoEditorHelper.createRandomFile(
+            mVideoEditor.getPath() + "/") + ".3gp";
+        int i = 0;
+        writeTestCaseHeader("testStressMultipleExport");
+        getBeginMemory();
+        final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
+            "m1", VideoItemFileName1, renderingMode);
+        mVideoEditor.addMediaItem(mediaItem1);
+        mediaItem1.setExtractBoundaries(0, 10000);
+
+        final MediaVideoItem mediaItem2 = new MediaVideoItem(mVideoEditor,
+            "m2", VideoItemFileName2, renderingMode);
+        mVideoEditor.addMediaItem(mediaItem2);
+        mediaItem2.setExtractBoundaries(0, 15000);
+
+        for ( i = 0; i < 50; i++) {
+            if(i%4 ==0){
+                final int aspectRatio = MediaProperties.ASPECT_RATIO_4_3;
+                mVideoEditor.setAspectRatio(aspectRatio);
+                mVideoEditor.export(outFilename, MediaProperties.HEIGHT_480,
+                    MediaProperties.BITRATE_256K,MediaProperties.ACODEC_AAC_LC,
+                        MediaProperties.VCODEC_H263,
+                        new ExportProgressListener() {
+                        public void onProgress(VideoEditor ve, String outFileName,
+                            int progress) {
+                        }
+                    });
+            }
+            if(i%4 ==1){
+                final int aspectRatio = MediaProperties.ASPECT_RATIO_5_3;
+                mVideoEditor.setAspectRatio(aspectRatio);
+                mVideoEditor.export(outFilename, MediaProperties.HEIGHT_144,
+                    MediaProperties.BITRATE_384K,MediaProperties.ACODEC_AAC_LC,
+                        MediaProperties.VCODEC_MPEG4,
+                        new ExportProgressListener() {
+                        public void onProgress(VideoEditor ve, String outFileName,
+                            int progress) {
+                        }
+                    });
+            }
+            if(i%4 ==2){
+                final int aspectRatio = MediaProperties.ASPECT_RATIO_11_9;
+                mVideoEditor.setAspectRatio(aspectRatio);
+                mVideoEditor.export(outFilename, MediaProperties.HEIGHT_144,
+                    MediaProperties.BITRATE_512K,MediaProperties.ACODEC_AAC_LC,
+                        MediaProperties.VCODEC_H264BP,
+                        new ExportProgressListener() {
+                        public void onProgress(VideoEditor ve, String outFileName,
+                            int progress) {
+                        }
+                    });
+            }
+            if(i%4 ==3){
+                final int aspectRatio = MediaProperties.ASPECT_RATIO_3_2;
+                mVideoEditor.setAspectRatio(aspectRatio);
+                mVideoEditor.export(outFilename, MediaProperties.HEIGHT_480,
+                    MediaProperties.BITRATE_800K,MediaProperties.ACODEC_AAC_LC,
+                        MediaProperties.VCODEC_H264BP,
+                        new ExportProgressListener() {
+                        public void onProgress(VideoEditor ve, String outFileName,
+                            int progress) {
+                        }
+                    });
+            }
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, false, i);
+            }
+        }
+        getAfterMemory_updateLog(loggingInfo, false, i);
+
+        /** Remove items and check for memory leak if any */
+        getBeginMemory();
+        mVideoEditor.removeMediaItem("m2");
+        mVideoEditor.removeMediaItem("m1");
+
+        getAfterMemory_updateLog(loggingInfo, true, i);
+    }
+
+    /**
+     * To stress test Media Item,Overlays,Transitions and Ken Burn
+     *
+     * @throws Exception
+     */
+    // TODO : remove TC_STR_011
+    @LargeTest
+    public void testStressOverlayTransKenBurn() throws Exception {
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String VideoItemFileName1 = INPUT_FILE_PATH +
+            "H264_BP_640x480_30fps_256kbps_1_17.mp4";
+        final String ImageItemFileName2 = INPUT_FILE_PATH +
+            "IMG_640x480.jpg";
+        final String OverlayFile3 = INPUT_FILE_PATH +
+            "IMG_640x480_Overlay1.png";
+        final String audioFilename4 = INPUT_FILE_PATH +
+            "AACLC_44.1kHz_256kbps_s_1_17.mp4";
+        int i = 0;
+        final String[] loggingInfo = new String[1];
+        writeTestCaseHeader("testStressOverlayTransKenBurn");
+        getBeginMemory();
+        for ( i = 0; i < 10; i++) {
+            final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
+                "m1" + i, VideoItemFileName1, renderingMode);
+            mVideoEditor.addMediaItem(mediaItem1);
+            mediaItem1.setExtractBoundaries(0, 10000);
+
+            final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
+                "m2" + i, ImageItemFileName2, 10000, renderingMode);
+            mVideoEditor.addMediaItem(mediaItem2);
+
+            final EffectColor effectColor1 =
+                mVideoEditorHelper.createEffectItem(mediaItem1, "effect1"+i,
+                    (mediaItem1.getDuration() - 4000), 4000,
+                    EffectColor.TYPE_SEPIA, 0);
+            mediaItem1.addEffect(effectColor1);
+
+            final TransitionCrossfade tranCrossfade =
+                new TransitionCrossfade("transCF" + i, mediaItem1,
+                    mediaItem2, 4000, Transition.BEHAVIOR_MIDDLE_FAST);
+            mVideoEditor.addTransition(tranCrossfade);
+
+            final Bitmap mBitmap =  mVideoEditorHelper.getBitmap(OverlayFile3,
+                640, 480);
+            final OverlayFrame overlayFrame =
+                mVideoEditorHelper.createOverlay(mediaItem1, "overlay" + i,
+                    mBitmap, 1000, 5000);
+            mediaItem1.addOverlay(overlayFrame);
+
+            final Rect startRect = new Rect((mediaItem2.getHeight() / 3),
+                (mediaItem2.getWidth() / 3), (mediaItem2.getHeight() / 2),
+                (mediaItem2.getWidth() / 2));
+            final Rect endRect = new Rect(0, 0, mediaItem2.getWidth(),
+                mediaItem2.getHeight());
+
+            final EffectKenBurns kbEffectOnMediaItem = new EffectKenBurns(
+                mediaItem2, "KBOnM2" + i, startRect, endRect, 500,
+                (mediaItem2.getDuration()-500));
+            mediaItem2.addEffect(kbEffectOnMediaItem);
+
+            if(i == 5) {
+                final AudioTrack audioTrack1 = new AudioTrack(mVideoEditor,
+                    "Audio Track1", audioFilename4);
+                mVideoEditor.addAudioTrack(audioTrack1);
+            }
+            getAfterMemory_updateLog(loggingInfo, false, i);
+        }
+        getAfterMemory_updateLog(loggingInfo, false, i);
+
+        /** Remove items and check for memory leak if any */
+        getBeginMemory();
+        for ( i = 0; i < 10; i++) {
+            MediaImageItem m2 = (MediaImageItem)mVideoEditor.getMediaItem("m2"+i);
+            MediaVideoItem m1 = (MediaVideoItem)mVideoEditor.getMediaItem("m1"+i);
+            m2.removeEffect("KBOnM2" + i);
+            m1.removeOverlay("overlay" + i);
+            mVideoEditor.removeTransition("transCF" + i);
+            m1.removeEffect("effect1" + i);
+            mVideoEditor.removeMediaItem("m2" + i);
+            mVideoEditor.removeMediaItem("m1" + i);
+            if(i == 5) {
+                mVideoEditor.removeAudioTrack("Audio Track1");
+            }
+            getAfterMemory_updateLog(loggingInfo, true, i);
+        }
+        getAfterMemory_updateLog(loggingInfo, true, i);
+    }
+
+    /**
+     * To test the performance : With an audio track with Video
+     *
+     * @throws Exception
+     */
+    // TODO : remove TC_STR_012
+    @LargeTest
+    public void testStressAudioTrackVideo() throws Exception {
+        final String videoItemFileName1 = INPUT_FILE_PATH +
+            "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
+        final String audioFilename1 = INPUT_FILE_PATH +
+            "AACLC_44.1kHz_256kbps_s_1_17.mp4";
+        final String audioFilename2 = INPUT_FILE_PATH +
+            "AMRNB_8KHz_12.2Kbps_m_1_17.3gp";
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final int audioVolume = 50;
+        final String[] loggingInfo = new String[1];
+        int i = 1;
+        writeTestCaseHeader("testStressAudioTrackVideo");
+        getBeginMemory();
+        final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
+            "mediaItem1", videoItemFileName1, renderingMode);
+        mVideoEditor.addMediaItem(mediaVideoItem);
+
+        final AudioTrack audioTrack1 = new AudioTrack(mVideoEditor,
+            "Audio Track1", audioFilename1);
+        audioTrack1.disableDucking();
+        audioTrack1.setVolume(audioVolume);
+        mVideoEditor.addAudioTrack(audioTrack1);
+
+        mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
+            public void onProgress(Object item, int action, int progress) {
+            }
+        });
+
+        mVideoEditor.removeAudioTrack("Audio Track1");
+
+        final AudioTrack audioTrack2 = new AudioTrack(mVideoEditor,
+            "Audio Track2", audioFilename2);
+        audioTrack2.enableLoop();
+
+        mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
+            public void onProgress(Object item, int action, int progress) {
+            }
+        });
+        getAfterMemory_updateLog(loggingInfo, false, i);
+
+        /** Remove items and check for memory leak if any */
+        getBeginMemory();
+        mVideoEditor.removeMediaItem("mediaItem1");
+
+        getAfterMemory_updateLog(loggingInfo, true, i);
+    }
+
+    /**
+     * To Test Stress : Story Board creation with out preview or export
+     *
+     * @throws Exception
+     */
+    // TODO : remove TC_STR_013
+    @LargeTest
+    public void testStressStoryBoard() throws Exception {
+        final String videoItemFileName1 = INPUT_FILE_PATH +
+            "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_161kbps_s_0_26.mp4";
+        final String videoItemFileName2 = INPUT_FILE_PATH +
+            "MPEG4_SP_854x480_15fps_256kbps_AACLC_16khz_48kbps_s_0_26.mp4";
+        final String videoItemFileName3= INPUT_FILE_PATH +
+            "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
+        final String imageItemFileName4 = INPUT_FILE_PATH +
+            "IMG_1600x1200.jpg";
+        final String imageItemFileName5 = INPUT_FILE_PATH +
+            "IMG_176x144.jpg";
+        final String audioFilename6 = INPUT_FILE_PATH +
+            "AMRNB_8KHz_12.2Kbps_m_1_17.3gp";
+        final String audioFilename7 = INPUT_FILE_PATH +
+            "AACLC_44.1kHz_256kbps_s_1_17.mp4";
+
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final int audioVolume = 50;
+        final String[] loggingInfo = new String[1];
+        int i = 1;
+
+        writeTestCaseHeader("testStressStoryBoard");
+        getBeginMemory();
+        final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
+            "m1", videoItemFileName1, renderingMode);
+        mediaItem1.setExtractBoundaries(0, 10000);
+        mVideoEditor.addMediaItem(mediaItem1);
+
+        final MediaVideoItem mediaItem2 = new MediaVideoItem(mVideoEditor,
+            "m2", videoItemFileName2, renderingMode);
+        mediaItem2.setExtractBoundaries(mediaItem2.getDuration()/4,
+            mediaItem2.getDuration()/2);
+        mVideoEditor.addMediaItem(mediaItem2);
+
+        final MediaVideoItem mediaItem3 = new MediaVideoItem(mVideoEditor,
+            "m3", videoItemFileName3, renderingMode);
+        mediaItem3.setExtractBoundaries(mediaItem3.getDuration()/2,
+            mediaItem3.getDuration());
+        mVideoEditor.addMediaItem(mediaItem3);
+
+        final MediaImageItem mediaItem4 = new MediaImageItem(mVideoEditor,
+            "m4", imageItemFileName4, 5000, renderingMode);
+        mVideoEditor.addMediaItem(mediaItem4);
+
+        final MediaImageItem mediaItem5 = new MediaImageItem(mVideoEditor,
+            "m5", imageItemFileName5, 5000, renderingMode);
+        mVideoEditor.addMediaItem(mediaItem5);
+
+        final TransitionCrossfade tranCrossfade =
+            new TransitionCrossfade("transCF", mediaItem2, mediaItem3, 2500,
+                Transition.BEHAVIOR_MIDDLE_FAST);
+        mVideoEditor.addTransition(tranCrossfade);
+
+        final TransitionCrossfade tranCrossfade1 =
+            new TransitionCrossfade("transCF1", mediaItem3, mediaItem4, 2500,
+                Transition.BEHAVIOR_MIDDLE_FAST);
+        mVideoEditor.addTransition(tranCrossfade1);
+
+        final AudioTrack audioTrack1 = new AudioTrack(mVideoEditor,
+            "Audio Track1", audioFilename6);
+        mVideoEditor.addAudioTrack(audioTrack1);
+
+        mVideoEditor.removeAudioTrack("Audio Track1");
+        final AudioTrack audioTrack2 = new AudioTrack(mVideoEditor,
+            "Audio Track2", audioFilename7);
+        mVideoEditor.addAudioTrack(audioTrack2);
+        audioTrack2.enableLoop();
+        getAfterMemory_updateLog(loggingInfo, false, i);
+
+        /** Remove items and check for memory leak if any */
+        getBeginMemory();
+        mVideoEditor.removeAudioTrack("Audio Track2");
+        mVideoEditor.removeTransition("transCF");
+        mVideoEditor.removeTransition("transCF1");
+        mVideoEditor.removeMediaItem("m5");
+        mVideoEditor.removeMediaItem("m4");
+        mVideoEditor.removeMediaItem("m3");
+        mVideoEditor.removeMediaItem("m2");
+        mVideoEditor.removeMediaItem("m1");
+
+        getAfterMemory_updateLog(loggingInfo, true, i);
+    }
+
+     /**
+     * To test the performance : With an audio track Only
+     *
+     * @throws Exception
+     */
+    // TODO : remove TC_STR_014
+    @LargeTest
+    public void testStressAudioTrackOnly() throws Exception {
+
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String AudioItemFileName1 = INPUT_FILE_PATH +
+            "AACLC_44.1kHz_256kbps_s_1_17.mp4";
+        final String[] loggingInfo = new String[1];
+        int i = 0;
+        writeTestCaseHeader("testStressAudioTrackOnly");
+        getBeginMemory();
+        for ( i = 0; i < 50; i++) {
+            final AudioTrack mediaItem1 = new AudioTrack(mVideoEditor,
+                "m1" + i, AudioItemFileName1);
+            mVideoEditor.addAudioTrack(mediaItem1);
+            mediaItem1.enableLoop();
+            mVideoEditor.removeAudioTrack("m1" + i);
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, false, i);
+            }
+        }
+        getAfterMemory_updateLog(loggingInfo, false, i);
+    }
+
+    /**
+     * This method will test thumbnail list extraction in a loop = 200 for Image
+     * Item
+     *
+     * @throws Exception
+     */
+    // TODO : remove TC_STR_016  -- New Test Case
+    @LargeTest
+    public void testStressThumbnailImageItem() throws Exception {
+        final String imageItemFileName = INPUT_FILE_PATH + "IMG_640x480.jpg";
+        final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
+        final String[] loggingInfo = new String[1];
+        int i = 0;
+        final MediaImageItem mediaImageItem = new MediaImageItem(mVideoEditor,
+            "m1", imageItemFileName, 5000, renderingMode);
+        writeTestCaseHeader("testStressThumbnailImageItem");
+        getBeginMemory();
+        for ( i = 0; i < 50; i++) {
+            if (i % 4 == 0) {
+                final Bitmap[] thumbNails = mediaImageItem.getThumbnailList(
+                    mediaImageItem.getWidth() / 2 ,
+                    mediaImageItem.getHeight() / 2, i, 5000, 2);
+                // Recycle this Bitmap array
+                for (int i1 = 0; i1 < thumbNails.length; i1++) {
+                    thumbNails[i1].recycle();
+                }
+            }
+            if (i % 4 == 1) {
+                final Bitmap[] thumbNails = mediaImageItem.getThumbnailList(
+                    mediaImageItem.getWidth() / 2,
+                    mediaImageItem.getHeight() * 3, i, 5000, 2);
+                // Recycle this Bitmap array
+                for (int i1 = 0; i1 < thumbNails.length; i1++) {
+                    thumbNails[i1].recycle();
+                }
+            }
+            if (i % 4 == 2) {
+                final Bitmap[] thumbNails = mediaImageItem.getThumbnailList(
+                    mediaImageItem.getWidth() * 2,
+                    mediaImageItem.getHeight() / 3, i, 5000, 2);
+                // Recycle this Bitmap array
+                for (int i1 = 0; i1 < thumbNails.length; i1++) {
+                    thumbNails[i1].recycle();
+                }
+            }
+            if (i % 4 == 3) {
+                final Bitmap[] thumbNails = mediaImageItem.getThumbnailList(
+                    mediaImageItem.getWidth(),
+                    mediaImageItem.getHeight(), i, 5000, 2);
+                // Recycle this Bitmap array
+                for (int i1 = 0; i1 < thumbNails.length; i1++) {
+                    thumbNails[i1].recycle();
+                }
+            }
+            if (i % 10 == 0) {
+                getAfterMemory_updateLog(loggingInfo, false, i);
+            }
+        }
+        getAfterMemory_updateLog(loggingInfo, false, i);
+    }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index f8809d7..9017ca3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -17,11 +17,7 @@
 package com.android.providers.settings;
 
 import java.io.FileNotFoundException;
-import java.io.UnsupportedEncodingException;
-import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
-import java.util.LinkedHashMap;
-import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -47,6 +43,7 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.LruCache;
 
 public class SettingsProvider extends ContentProvider {
     private static final String TAG = "SettingsProvider";
@@ -293,7 +290,7 @@
             "" + (MAX_CACHE_ENTRIES + 1) /* limit */);
         try {
             synchronized (cache) {
-                cache.clear();
+                cache.evictAll();
                 cache.setFullyMatchesDisk(true);  // optimistic
                 int rows = 0;
                 while (c.moveToNext()) {
@@ -359,8 +356,8 @@
     // possibly with a null value, or null on failure.
     private Bundle lookupValue(String table, SettingsCache cache, String key) {
         synchronized (cache) {
-            if (cache.containsKey(key)) {
-                Bundle value = cache.get(key);
+            Bundle value = cache.get(key);
+            if (value != null) {
                 if (value != TOO_LARGE_TO_CACHE_MARKER) {
                     return value;
                 }
@@ -725,13 +722,13 @@
      * associated helper functions to keep cache coherent with the
      * database.
      */
-    private static final class SettingsCache extends LinkedHashMap<String, Bundle> {
+    private static final class SettingsCache extends LruCache<String, Bundle> {
 
         private final String mCacheName;
         private boolean mCacheFullyMatchesDisk = false;  // has the whole database slurped.
 
         public SettingsCache(String name) {
-            super(MAX_CACHE_ENTRIES, 0.75f /* load factor */, true /* access ordered */);
+            super(MAX_CACHE_ENTRIES);
             mCacheName = name;
         }
 
@@ -751,14 +748,8 @@
         }
 
         @Override
-        protected boolean removeEldestEntry(Map.Entry eldest) {
-            if (size() <= MAX_CACHE_ENTRIES) {
-                return false;
-            }
-            synchronized (this) {
-                mCacheFullyMatchesDisk = false;
-            }
-            return true;
+        protected synchronized void entryEvicted(String key, Bundle value) {
+            mCacheFullyMatchesDisk = false;
         }
 
         /**
@@ -772,7 +763,7 @@
             Bundle bundle = (value == null) ? NULL_SETTING : Bundle.forPair("value", value);
             if (value == null || value.length() <= MAX_CACHE_ENTRY_SIZE) {
                 synchronized (this) {
-                    if (!containsKey(key)) {
+                    if (get(key) == null) {
                         put(key, bundle);
                     }
                 }
@@ -826,7 +817,7 @@
                 return;
             }
             synchronized (cache) {
-                cache.clear();
+                cache.evictAll();
                 cache.mCacheFullyMatchesDisk = false;
             }
         }
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png
new file mode 100644
index 0000000..1aea612
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png
new file mode 100644
index 0000000..425535e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_4g.png
new file mode 100644
index 0000000..fcad363
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.png
new file mode 100644
index 0000000..4ff7db3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_4g.png
new file mode 100644
index 0000000..2c4a07f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_4g.png
new file mode 100644
index 0000000..879c703
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inadnout_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inadnout_e.png
new file mode 100644
index 0000000..61a7503
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inadnout_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_4g.png
new file mode 100644
index 0000000..c5edf2c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_4g.png
new file mode 100644
index 0000000..ddf88be
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
index 78ece9e..c77e61e 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
index 31fc1b0..b9f721a 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png
new file mode 100644
index 0000000..cff969e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
index 19adb4b..d2d7ab3 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
index fd419ea..83ce6d0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
index 94e77ae..abe511f 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png
index 91328c0..d685af8 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png
index 2fee6924..8c697a1 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png
new file mode 100644
index 0000000..9a4b807
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png
index d0968aa..eb11d04 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png
index 991228b..6e54de0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png
index ae03e38..5bfb33b 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png
index 97b011e..119067b 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png
index a826866..a70cc2e 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_4g.png
new file mode 100644
index 0000000..ea3dba7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png
index f6a6891..53221b9 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png
index 19b9816..11d44d0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png
index f8c0961..9defd79 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png
index 22deb70..136576d 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png
index c7c1b49..26ca31f 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.png
new file mode 100644
index 0000000..de8c5ee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png
index d9a0702..64dbf3c 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png
index 6beed8a..34923fb 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png
index e4179c1..506b5c6 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png
index 4b2f86d..163976f 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png
index 6779604..a6af649 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_4g.png
new file mode 100644
index 0000000..0c08e52
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png
index 1309a97..1d02edb 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png
index 2fc1e8e..edc9536 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png
index 0eef2c1..8376817 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
index f8904e2..ecef547 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
index 3ef306e..a7c48b6 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_4g.png
new file mode 100644
index 0000000..f4bcd9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
index 2ff6d90..b46bb3a 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
index 8ff49b0..e8b70f2 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
index f416203..4e23c4e 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inadnout_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inadnout_e.png
new file mode 100644
index 0000000..ced9175
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inadnout_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
index 24b7daa..92d4a19 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
index 5ea9142..a208736 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_4g.png
new file mode 100644
index 0000000..f407bc9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
index 002bf46..b8a65c2 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
index 924b84f..a978b68 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
index bd0d1ca..710dd52 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
index f583eec..a7b35e4 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_4g.png
new file mode 100644
index 0000000..bb05449
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
index 66940eaf..a144222 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
index 0381f52..b0eafb6 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
index 0b84fe8..f6b83d0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
Binary files differ
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index afb73a9..60fb61d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -668,7 +668,7 @@
     }
 
     public void updateNotification(IBinder key, StatusBarNotification notification) {
-        if (DEBUG) Slog.d(TAG, "updateNotification(" + key + " -> " + notification + ") // TODO");
+        if (DEBUG) Slog.d(TAG, "updateNotification(" + key + " -> " + notification + ")");
 
         final NotificationData.Entry oldEntry = mNotificationData.findByKey(key);
         if (oldEntry == null) {
@@ -685,7 +685,8 @@
             Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
                     + " ongoing=" + oldNotification.isOngoing()
                     + " expanded=" + oldEntry.expanded
-                    + " contentView=" + oldContentView);
+                    + " contentView=" + oldContentView
+                    + " rowParent=" + oldEntry.row.getParent());
             Slog.d(TAG, "new notification: when=" + notification.notification.when
                     + " ongoing=" + oldNotification.isOngoing()
                     + " contentView=" + contentView);
@@ -806,16 +807,17 @@
             }
         }
         if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-            if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-                Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
-                mTicker.halt();
-            } else {
-                Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: no");
-            }
-            // refresh icons to show either notifications or the DND message
             mNotificationDNDMode = Prefs.read(mContext)
                         .getBoolean(Prefs.DO_NOT_DISTURB_PREF, Prefs.DO_NOT_DISTURB_DEFAULT);
-            Slog.d(TAG, "DND: " + mNotificationDNDMode);
+
+            if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+                Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: yes" + (mNotificationDNDMode?" (DND)":""));
+                mTicker.halt();
+            } else {
+                Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: no" + (mNotificationDNDMode?" (DND)":""));
+            }
+
+            // refresh icons to show either notifications or the DND message
             reloadAllNotificationIcons();
         } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
             if ((state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
@@ -1241,29 +1243,34 @@
 
         if (mIconLayout == null) return;
 
+        // first, populate the main notification panel
+        loadNotificationPanel();
+
         final LinearLayout.LayoutParams params
             = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight);
 
         // alternate behavior in DND mode
-        if (mNotificationDNDMode && mIconLayout.getChildCount() == 0) {
-            final StatusBarIconView iconView = new StatusBarIconView(mContext, "_dnd");
-            iconView.setImageResource(R.drawable.ic_notification_dnd);
-            iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-            iconView.setPadding(mIconHPadding, 0, mIconHPadding, 0);
+        if (mNotificationDNDMode) {
+            if (mIconLayout.getChildCount() == 0) {
+                final StatusBarIconView iconView = new StatusBarIconView(mContext, "_dnd");
+                iconView.setImageResource(R.drawable.ic_notification_dnd);
+                iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+                iconView.setPadding(mIconHPadding, 0, mIconHPadding, 0);
 
-            final Notification dndNotification = new Notification.Builder(mContext)
-                .setContentTitle(mContext.getText(R.string.notifications_off_title))
-                .setContentText(mContext.getText(R.string.notifications_off_text))
-                .setSmallIcon(R.drawable.ic_notification_dnd)
-                .setOngoing(true)
-                .getNotification();
+                final Notification dndNotification = new Notification.Builder(mContext)
+                    .setContentTitle(mContext.getText(R.string.notifications_off_title))
+                    .setContentText(mContext.getText(R.string.notifications_off_text))
+                    .setSmallIcon(R.drawable.ic_notification_dnd)
+                    .setOngoing(true)
+                    .getNotification();
 
-            mNotificationDNDDummyEntry = new NotificationData.Entry(
-                    null,
-                    new StatusBarNotification("", 0, "", 0, 0, dndNotification),
-                    iconView);
+                mNotificationDNDDummyEntry = new NotificationData.Entry(
+                        null,
+                        new StatusBarNotification("", 0, "", 0, 0, dndNotification),
+                        iconView);
 
-            mIconLayout.addView(iconView, params);
+                mIconLayout.addView(iconView, params);
+            }
 
             return;
         }
@@ -1305,8 +1312,6 @@
                 mIconLayout.addView(v, i, params);
             }
         }
-
-        loadNotificationPanel();
     }
 
     private void loadNotificationPanel() {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 156391e..f6649fd 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1448,7 +1448,13 @@
                                 | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
                 if (shortcutIntent != null) {
                     shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    mContext.startActivity(shortcutIntent);
+                    try {
+                        mContext.startActivity(shortcutIntent);
+                    } catch (ActivityNotFoundException ex) {
+                        Slog.w(TAG, "Dropping shortcut key combination because "
+                                + "the activity to which it is registered was not found: "
+                                + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
+                    }
                     return null;
                 }
             }
@@ -2438,6 +2444,17 @@
         return mKeyguardMediator.isShowingAndNotHidden();
     }
 
+
+    /** {@inheritDoc} */
+    public boolean isKeyguardLocked() {
+        return keyguardOn();
+    }
+
+    /** {@inheritDoc} */
+    public boolean isKeyguardSecure() {
+        return mKeyguardMediator.isSecure();
+    }
+
     /** {@inheritDoc} */
     public boolean inKeyguardRestrictedKeyInputMode() {
         return mKeyguardMediator.isInputRestricted();
@@ -2463,6 +2480,15 @@
     public int rotationForOrientationLw(int orientation, int lastRotation,
             boolean displayEnabled) {
 
+        if (false) {
+            Slog.v(TAG, "rotationForOrientationLw(orient="
+                        + orientation + ", last=" + lastRotation
+                        + "); user=" + mUserRotation + " "
+                        + ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED)
+                            ? "USER_ROTATION_LOCKED" : "")
+                        );
+        }
+
         if (mPortraitRotation < 0) {
             // Initialize the rotation angles for each orientation once.
             Display d = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
@@ -2544,6 +2570,16 @@
     }
 
     private int getCurrentLandscapeRotation(int lastRotation) {
+        // if the user has locked rotation, we ignore the sensor 
+        if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
+            if (isLandscapeOrSeascape(mUserRotation)) {
+                return mUserRotation;
+            } else {
+                // it seems odd to obey the sensor at all if rotation lock is enabled
+                return mLandscapeRotation;
+            }
+        }
+
         int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
         if (isLandscapeOrSeascape(sensorRotation)) {
             return sensorRotation;
@@ -2561,6 +2597,16 @@
     }
 
     private int getCurrentPortraitRotation(int lastRotation) {
+        // if the user has locked rotation, we ignore the sensor 
+        if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
+            if (isAnyPortrait(mUserRotation)) {
+                return mUserRotation;
+            } else {
+                // it seems odd to obey the sensor at all if rotation lock is enabled
+                return mPortraitRotation;
+            }
+        }
+
         int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
         if (isAnyPortrait(sensorRotation)) {
             return sensorRotation;
@@ -2581,15 +2627,15 @@
     // User rotation: to be used when all else fails in assigning an orientation to the device
     public void setUserRotationMode(int mode, int rot) {
         ContentResolver res = mContext.getContentResolver();
-        mUserRotationMode = mode;
+
+        // mUserRotationMode and mUserRotation will be assigned by the content observer
         if (mode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
-            mUserRotation = rot;
-            Settings.System.putInt(res,
-                    Settings.System.ACCELEROMETER_ROTATION,
-                    0);
             Settings.System.putInt(res,
                     Settings.System.USER_ROTATION,
                     rot);
+            Settings.System.putInt(res,
+                    Settings.System.ACCELEROMETER_ROTATION,
+                    0);
         } else {
             Settings.System.putInt(res,
                     Settings.System.ACCELEROMETER_ROTATION,
@@ -2907,7 +2953,7 @@
                 pw.print(" mDeskDockRotation="); pw.println(mDeskDockRotation);
         pw.print(prefix); pw.print("mUserRotationMode="); pw.print(mUserRotationMode);
                 pw.print(" mUserRotation="); pw.print(mUserRotation);
-                pw.print("mAllowAllRotations="); pw.println(mAllowAllRotations);
+                pw.print(" mAllowAllRotations="); pw.println(mAllowAllRotations);
         pw.print(prefix); pw.print("mAccelerometerDefault="); pw.print(mAccelerometerDefault);
                 pw.print(" mCurrentAppOrientation="); pw.println(mCurrentAppOrientation);
         pw.print(prefix); pw.print("mCarDockEnablesAccelerometer=");
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 3d8ca7a..a09e16b 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -727,17 +727,30 @@
 }
 
 // take a picture - image is returned in callback
-status_t CameraService::Client::takePicture() {
-    LOG1("takePicture (pid %d)", getCallingPid());
+status_t CameraService::Client::takePicture(int msgType) {
+    LOG1("takePicture (pid %d): 0x%x", getCallingPid(), msgType);
 
     Mutex::Autolock lock(mLock);
     status_t result = checkPidAndHardware();
     if (result != NO_ERROR) return result;
 
-    enableMsgType(CAMERA_MSG_SHUTTER |
-                  CAMERA_MSG_POSTVIEW_FRAME |
-                  CAMERA_MSG_RAW_IMAGE |
-                  CAMERA_MSG_COMPRESSED_IMAGE);
+    if ((msgType & CAMERA_MSG_RAW_IMAGE) &&
+        (msgType & CAMERA_MSG_RAW_IMAGE_NOTIFY)) {
+        LOGE("CAMERA_MSG_RAW_IMAGE and CAMERA_MSG_RAW_IMAGE_NOTIFY"
+                " cannot be both enabled");
+        return BAD_VALUE;
+    }
+
+    // We only accept picture related message types
+    // and ignore other types of messages for takePicture().
+    int picMsgType = msgType
+                        & (CAMERA_MSG_SHUTTER |
+                           CAMERA_MSG_POSTVIEW_FRAME |
+                           CAMERA_MSG_RAW_IMAGE |
+                           CAMERA_MSG_RAW_IMAGE_NOTIFY |
+                           CAMERA_MSG_COMPRESSED_IMAGE);
+
+    enableMsgType(picMsgType);
 
     return mHardware->takePicture();
 }
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index ccb9cf7..1c43b00 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -108,7 +108,7 @@
         virtual void            releaseRecordingFrame(const sp<IMemory>& mem);
         virtual status_t        autoFocus();
         virtual status_t        cancelAutoFocus();
-        virtual status_t        takePicture();
+        virtual status_t        takePicture(int msgType);
         virtual status_t        setParameters(const String8& params);
         virtual String8         getParameters() const;
         virtual status_t        sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index ef984d4..2e3f0bd 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -3211,14 +3211,52 @@
                     // be used as modifiers) but it will ensure that fallback keys do not
                     // get stuck.  This takes care of the case where the application does not handle
                     // the original DOWN so we generate a fallback DOWN but it does handle
-                    // the original UP in which case we would not generate the fallback UP.
+                    // the original UP in which case we want to send a fallback CANCEL.
                     synthesizeCancelationEventsForConnectionLocked(connection,
                             InputState::CANCEL_FALLBACK_EVENTS,
-                            "application handled a non-fallback event, canceling all fallback events");
+                            "application handled a non-fallback event, "
+                            "canceling all fallback events");
+                    connection->originalKeyCodeForFallback = -1;
                 } else {
-                    // If the application did not handle a non-fallback key, then ask
-                    // the policy what to do with it.  We might generate a fallback key
-                    // event here.
+                    // If the application did not handle a non-fallback key, first check
+                    // that we are in a good state to handle the fallback key.  Then ask
+                    // the policy what to do with it.
+                    if (connection->originalKeyCodeForFallback < 0) {
+                        if (keyEntry->action != AKEY_EVENT_ACTION_DOWN
+                                || keyEntry->repeatCount != 0) {
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+                            LOGD("Unhandled key event: Skipping fallback since this "
+                                    "is not an initial down.  "
+                                    "keyCode=%d, action=%d, repeatCount=%d",
+                                    keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount);
+#endif
+                            goto SkipFallback;
+                        }
+
+                        // Start handling the fallback key on DOWN.
+                        connection->originalKeyCodeForFallback = keyEntry->keyCode;
+                    } else {
+                        if (keyEntry->keyCode != connection->originalKeyCodeForFallback) {
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+                            LOGD("Unhandled key event: Skipping fallback since there is "
+                                    "already a different fallback in progress.  "
+                                    "keyCode=%d, originalKeyCodeForFallback=%d",
+                                    keyEntry->keyCode, connection->originalKeyCodeForFallback);
+#endif
+                            goto SkipFallback;
+                        }
+
+                        // Finish handling the fallback key on UP.
+                        if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
+                            connection->originalKeyCodeForFallback = -1;
+                        }
+                    }
+
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+                    LOGD("Unhandled key event: Asking policy to perform fallback action.  "
+                            "keyCode=%d, action=%d, repeatCount=%d",
+                            keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount);
+#endif
                     KeyEvent event;
                     initializeKeyEvent(&event, keyEntry);
 
@@ -3248,6 +3286,12 @@
                         keyEntry->downTime = event.getDownTime();
                         keyEntry->syntheticRepeat = false;
 
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+                        LOGD("Unhandled key event: Dispatching fallback key.  "
+                                "fallbackKeyCode=%d, fallbackMetaState=%08x",
+                                keyEntry->keyCode, keyEntry->metaState);
+#endif
+
                         dispatchEntry->inProgress = false;
                         startDispatchCycleLocked(now(), connection);
                         return;
@@ -3257,6 +3301,7 @@
         }
     }
 
+SkipFallback:
     startNextDispatchCycleLocked(now(), connection);
 }
 
@@ -3715,7 +3760,8 @@
         const sp<InputWindowHandle>& inputWindowHandle) :
         status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
         inputPublisher(inputChannel),
-        lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX) {
+        lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX),
+        originalKeyCodeForFallback(-1) {
 }
 
 InputDispatcher::Connection::~Connection() {
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 7abe014..304b1bb 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -682,6 +682,7 @@
 
         nsecs_t lastEventTime; // the time when the event was originally captured
         nsecs_t lastDispatchTime; // the time when the last event was dispatched
+        int32_t originalKeyCodeForFallback; // original keycode for fallback in progress, -1 if none
 
         explicit Connection(const sp<InputChannel>& inputChannel,
                 const sp<InputWindowHandle>& inputWindowHandle);
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index e54e215..7af60c5 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -4765,7 +4765,7 @@
                 final File externalMediaDir = Environment
                         .getExternalStorageAppMediaDirectory(mStats.packageName);
                 mStats.externalMediaSize = mContainerService
-                        .calculateDirectorySize(externalCacheDir.getPath());
+                        .calculateDirectorySize(externalMediaDir.getPath());
 
                 final File externalObbDir = Environment
                         .getExternalStorageAppObbDirectory(mStats.packageName);
diff --git a/services/java/com/android/server/UsbService.java b/services/java/com/android/server/UsbService.java
index af4c425..1bc203e 100644
--- a/services/java/com/android/server/UsbService.java
+++ b/services/java/com/android/server/UsbService.java
@@ -44,7 +44,11 @@
 import java.util.HashMap;
 
 /**
- * <p>UsbService monitors for changes to USB state.
+ * UsbService monitors for changes to USB state.
+ * This includes code for both USB host support (where the android device is the host)
+ * as well as USB device support (android device is connected to a USB host).
+ * Accessory mode is a special case of USB device mode, where the android device is
+ * connected to a USB host that supports the android accessory protocol.
  */
 class UsbService extends IUsbManager.Stub {
     private static final String TAG = UsbService.class.getSimpleName();
@@ -63,7 +67,9 @@
     private static final String USB_COMPOSITE_CLASS_PATH =
             "/sys/class/usb_composite";
 
-    private static final int MSG_UPDATE = 0;
+    private static final int MSG_UPDATE_STATE = 0;
+    private static final int MSG_FUNCTION_ENABLED = 1;
+    private static final int MSG_FUNCTION_DISABLED = 2;
 
     // Delay for debouncing USB disconnects.
     // We often get rapid connect/disconnect events when enabling USB functions,
@@ -79,7 +85,6 @@
     private int mLastConfiguration = -1;
 
     // lists of enabled and disabled USB functions (for USB device mode)
-    // synchronize on mEnabledFunctions when using either of these lists
     private final ArrayList<String> mEnabledFunctions = new ArrayList<String>();
     private final ArrayList<String> mDisabledFunctions = new ArrayList<String>();
 
@@ -90,26 +95,48 @@
     private final String[] mHostBlacklist;
 
     private boolean mSystemReady;
+
     private UsbAccessory mCurrentAccessory;
+    // functions to restore after exiting accessory mode
+    private final ArrayList<String> mAccessoryRestoreFunctions = new ArrayList<String>();
 
     private final Context mContext;
+    private final Object mLock = new Object();
 
-    private final void functionEnabled(String function, boolean enabled) {
-        synchronized (mEnabledFunctions) {
-            if (enabled) {
-                if (!mEnabledFunctions.contains(function)) {
-                    mEnabledFunctions.add(function);
+    /*
+     * Handles USB function enable/disable events (device mode)
+     */
+    private final void functionEnabledLocked(String function, boolean enabled) {
+        boolean enteringAccessoryMode =
+            (enabled && UsbManager.USB_FUNCTION_ACCESSORY.equals(function));
+
+        if (enteringAccessoryMode) {
+            // keep a list of functions to reenable after exiting accessory mode
+            mAccessoryRestoreFunctions.clear();
+            int count = mEnabledFunctions.size();
+            for (int i = 0; i < count; i++) {
+                String f = mEnabledFunctions.get(i);
+                // RNDIS should not be restored and adb is handled automatically
+                if (!UsbManager.USB_FUNCTION_RNDIS.equals(f) &&
+                    !UsbManager.USB_FUNCTION_ADB.equals(f) &&
+                    !UsbManager.USB_FUNCTION_ACCESSORY.equals(f)) {
+                    mAccessoryRestoreFunctions.add(f);
                 }
-                mDisabledFunctions.remove(function);
-            } else {
-                if (!mDisabledFunctions.contains(function)) {
-                    mDisabledFunctions.add(function);
-                }
-                mEnabledFunctions.remove(function);
             }
         }
+        if (enabled) {
+            if (!mEnabledFunctions.contains(function)) {
+                mEnabledFunctions.add(function);
+            }
+            mDisabledFunctions.remove(function);
+        } else {
+            if (!mDisabledFunctions.contains(function)) {
+                mDisabledFunctions.add(function);
+            }
+            mEnabledFunctions.remove(function);
+        }
 
-        if (enabled && UsbManager.USB_FUNCTION_ACCESSORY.equals(function)) {
+        if (enteringAccessoryMode) {
             String[] strings = nativeGetAccessoryStrings();
             if (strings != null) {
                 Log.d(TAG, "entering USB accessory mode");
@@ -136,6 +163,9 @@
         }
     }
 
+    /*
+     * Listens for uevent messages from the kernel to monitor the USB state (device mode)
+     */
     private final UEventObserver mUEventObserver = new UEventObserver() {
         @Override
         public void onUEvent(UEventObserver.UEvent event) {
@@ -143,7 +173,7 @@
                 Slog.v(TAG, "USB UEVENT: " + event.toString());
             }
 
-            synchronized (this) {
+            synchronized (mLock) {
                 String name = event.get("SWITCH_NAME");
                 String state = event.get("SWITCH_STATE");
                 if (name != null && state != null) {
@@ -172,8 +202,11 @@
                     if (function != null && enabledStr != null) {
                         // Note: we do not broadcast a change when a function is enabled or disabled.
                         // We just record the state change for the next broadcast.
-                        boolean enabled = "1".equals(enabledStr);
-                        functionEnabled(function, enabled);
+                        int what = ("1".equals(enabledStr) ?
+                                MSG_FUNCTION_ENABLED : MSG_FUNCTION_DISABLED);
+                        Message msg = Message.obtain(mHandler, what);
+                        msg.obj = function;
+                        mHandler.sendMessage(msg);
                     }
                 }
             }
@@ -197,6 +230,7 @@
     private final void init() {
         char[] buffer = new char[1024];
 
+        // Read initial USB state (device mode)
         mConfiguration = -1;
         try {
             FileReader file = new FileReader(USB_CONNECTED_PATH);
@@ -217,21 +251,20 @@
         if (mConfiguration < 0)
             return;
 
+        // Read initial list of enabled and disabled functions (device mode)
         try {
-            synchronized (mEnabledFunctions) {
-                File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles();
-                for (int i = 0; i < files.length; i++) {
-                    File file = new File(files[i], "enable");
-                    FileReader reader = new FileReader(file);
-                    int len = reader.read(buffer, 0, 1024);
-                    reader.close();
-                    int value = Integer.valueOf((new String(buffer, 0, len)).trim());
-                    String functionName = files[i].getName();
-                    if (value == 1) {
-                        mEnabledFunctions.add(functionName);
-                    } else {
-                        mDisabledFunctions.add(functionName);
-                    }
+            File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles();
+            for (int i = 0; i < files.length; i++) {
+                File file = new File(files[i], "enable");
+                FileReader reader = new FileReader(file);
+                int len = reader.read(buffer, 0, 1024);
+                reader.close();
+                int value = Integer.valueOf((new String(buffer, 0, len)).trim());
+                String functionName = files[i].getName();
+                if (value == 1) {
+                    mEnabledFunctions.add(functionName);
+                } else {
+                    mDisabledFunctions.add(functionName);
                 }
             }
         } catch (FileNotFoundException e) {
@@ -251,6 +284,7 @@
         return false;
     }
 
+    /* returns true if the USB device should not be accessible by applications (host mode) */
     private boolean isBlackListed(int clazz, int subClass, int protocol) {
         // blacklist hubs
         if (clazz == UsbConstants.USB_CLASS_HUB) return true;
@@ -264,7 +298,7 @@
         return false;
     }
 
-    // called from JNI in monitorUsbHostBus()
+    /* Called from JNI in monitorUsbHostBus() to report new USB devices (host mode) */
     private void usbDeviceAdded(String deviceName, int vendorID, int productID,
             int deviceClass, int deviceSubclass, int deviceProtocol,
             /* array of quintuples containing id, class, subclass, protocol
@@ -279,7 +313,7 @@
             return;
         }
 
-        synchronized (mDevices) {
+        synchronized (mLock) {
             if (mDevices.get(deviceName) != null) {
                 Log.w(TAG, "device already on mDevices list: " + deviceName);
                 return;
@@ -338,9 +372,9 @@
         }
     }
 
-    // called from JNI in monitorUsbHostBus()
+    /* Called from JNI in monitorUsbHostBus to report USB device removal (host mode) */
     private void usbDeviceRemoved(String deviceName) {
-        synchronized (mDevices) {
+        synchronized (mLock) {
             UsbDevice device = mDevices.remove(deviceName);
             if (device != null) {
                 Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
@@ -363,7 +397,7 @@
     }
 
     void systemReady() {
-        synchronized (this) {
+        synchronized (mLock) {
             if (mContext.getResources().getBoolean(
                     com.android.internal.R.bool.config_hasUsbHostSupport)) {
                 // start monitoring for connected USB devices
@@ -375,21 +409,27 @@
         }
     }
 
+    /*
+     * Sends a message to update the USB connected and configured state (device mode).
+     * If delayed is true, then we add a small delay in sending the message to debounce
+     * the USB connection when enabling USB tethering.
+     */
     private final void update(boolean delayed) {
-        mHandler.removeMessages(MSG_UPDATE);
-        mHandler.sendEmptyMessageDelayed(MSG_UPDATE, delayed ? UPDATE_DELAY : 0);
+        mHandler.removeMessages(MSG_UPDATE_STATE);
+        mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STATE, delayed ? UPDATE_DELAY : 0);
     }
 
-    /* Returns a list of all currently attached USB devices */
+    /* Returns a list of all currently attached USB devices (host mdoe) */
     public void getDeviceList(Bundle devices) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null);
-        synchronized (mDevices) {
+        synchronized (mLock) {
             for (String name : mDevices.keySet()) {
                 devices.putParcelable(name, mDevices.get(name));
             }
         }
     }
 
+    /* Opens the specified USB device (host mode) */
     public ParcelFileDescriptor openDevice(String deviceName) {
         if (isBlackListed(deviceName)) {
             throw new SecurityException("USB device is on a restricted bus");
@@ -403,34 +443,37 @@
         return nativeOpenDevice(deviceName);
     }
 
+    /* returns the currently attached USB accessory (device mode) */
     public UsbAccessory getCurrentAccessory() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null);
         return mCurrentAccessory;
     }
 
+    /* opens the currently attached USB accessory (device mode) */
     public ParcelFileDescriptor openAccessory() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null);
         return nativeOpenAccessory();
     }
 
+    /*
+     * This handler is for deferred handling of events related to device mode and accessories.
+     */
     private final Handler mHandler = new Handler() {
-        private void addEnabledFunctions(Intent intent) {
-            synchronized (mEnabledFunctions) {
+        private void addEnabledFunctionsLocked(Intent intent) {
             // include state of all USB functions in our extras
-                for (int i = 0; i < mEnabledFunctions.size(); i++) {
-                    intent.putExtra(mEnabledFunctions.get(i), UsbManager.USB_FUNCTION_ENABLED);
-                }
-                for (int i = 0; i < mDisabledFunctions.size(); i++) {
-                    intent.putExtra(mDisabledFunctions.get(i), UsbManager.USB_FUNCTION_DISABLED);
-                }
+            for (int i = 0; i < mEnabledFunctions.size(); i++) {
+                intent.putExtra(mEnabledFunctions.get(i), UsbManager.USB_FUNCTION_ENABLED);
+            }
+            for (int i = 0; i < mDisabledFunctions.size(); i++) {
+                intent.putExtra(mDisabledFunctions.get(i), UsbManager.USB_FUNCTION_DISABLED);
             }
         }
 
         @Override
         public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_UPDATE:
-                    synchronized (this) {
+            synchronized (mLock) {
+                switch (msg.what) {
+                    case MSG_UPDATE_STATE:
                         if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) {
                             if (mConnected == 0 && mCurrentAccessory != null) {
                                 // turn off accessory mode when we are disconnected
@@ -438,6 +481,14 @@
                                         UsbManager.USB_FUNCTION_ACCESSORY, false)) {
                                     Log.d(TAG, "exited USB accessory mode");
 
+                                    // restore previously enabled functions
+                                    for (String function : mAccessoryRestoreFunctions) {
+                                        if (UsbManager.setFunctionEnabled(function, true)) {
+                                            Log.e(TAG, "could not reenable function " + function);
+                                        }
+                                    }
+                                    mAccessoryRestoreFunctions.clear();
+
                                     Intent intent = new Intent(
                                             UsbManager.ACTION_USB_ACCESSORY_DETACHED);
                                     intent.putExtra(UsbManager.EXTRA_ACCESSORY, mCurrentAccessory);
@@ -468,17 +519,23 @@
                             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
                             intent.putExtra(UsbManager.USB_CONNECTED, mConnected != 0);
                             intent.putExtra(UsbManager.USB_CONFIGURATION, mConfiguration);
-                            addEnabledFunctions(intent);
+                            addEnabledFunctionsLocked(intent);
                             mContext.sendStickyBroadcast(intent);
                         }
-                    }
-                    break;
+                        break;
+                    case MSG_FUNCTION_ENABLED:
+                    case MSG_FUNCTION_DISABLED:
+                        functionEnabledLocked((String)msg.obj, msg.what == MSG_FUNCTION_ENABLED);
+                        break;
+                }
             }
         }
     };
 
+    // host support
     private native void monitorUsbHostBus();
     private native ParcelFileDescriptor nativeOpenDevice(String deviceName);
+    // accessory support
     private native String[] nativeGetAccessoryStrings();
     private native ParcelFileDescriptor nativeOpenAccessory();
 }
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index cc25e8d..f9b94a3 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -96,6 +96,9 @@
     private boolean mDeviceIdle;
     private int mPluggedType;
 
+    /* Chipset supports background scan */
+    private final boolean mBackgroundScanSupported;
+
     // true if the user enabled Wifi while in airplane mode
     private AtomicBoolean mAirplaneModeOverwridden = new AtomicBoolean(false);
 
@@ -369,6 +372,9 @@
                 Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
         mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler());
         mNotificationEnabledSettingObserver.register();
+
+        mBackgroundScanSupported = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_wifi_background_scan_support);
     }
 
     /**
@@ -900,6 +906,9 @@
                 reportStartWorkSource();
                 evaluateTrafficStatsPolling();
                 mWifiStateMachine.enableRssiPolling(true);
+                if (mBackgroundScanSupported) {
+                    mWifiStateMachine.enableBackgroundScan(false);
+                }
                 mWifiStateMachine.enableAllNetworks();
                 updateWifiState();
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
@@ -909,6 +918,9 @@
                 mScreenOff = true;
                 evaluateTrafficStatsPolling();
                 mWifiStateMachine.enableRssiPolling(false);
+                if (mBackgroundScanSupported) {
+                    mWifiStateMachine.enableBackgroundScan(true);
+                }
                 /*
                  * Set a timer to put Wi-Fi to sleep, but only if the screen is off
                  * AND the "stay on while plugged in" setting doesn't match the
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 34f3618..b1833c4 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -1,6 +1,19 @@
-/**
- * 
+/*
+ * 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.server.wm;
 
 import android.graphics.Rect;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index a598ce9..b7cc324 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -4410,6 +4410,14 @@
         return mPolicy.inKeyguardRestrictedKeyInputMode();
     }
 
+    public boolean isKeyguardLocked() {
+        return mPolicy.isKeyguardLocked();
+    }
+
+    public boolean isKeyguardSecure() {
+        return mPolicy.isKeyguardSecure();
+    }
+
     public void closeSystemDialogs(String reason) {
         synchronized(mWindowMap) {
             for (int i=mWindows.size()-1; i>=0; i--) {
@@ -4822,21 +4830,25 @@
 
     public void freezeRotation() {
         if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
-                "setRotation()")) {
+                "freezeRotation()")) {
             throw new SecurityException("Requires SET_ORIENTATION permission");
         }
 
+        if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation);
+
         mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED, mRotation);
         setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false, 0);
     }
 
     public void thawRotation() {
         if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
-                "setRotation()")) {
+                "thawRotation()")) {
             throw new SecurityException("Requires SET_ORIENTATION permission");
         }
 
-        mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 0);
+        if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation);
+
+        mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 777); // rot not used
         setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false, 0);
     }
 
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index a75e41d..6d4ad9a 100755
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -217,82 +217,10 @@
     create_thread_callback,
 };
 
-static const GpsInterface* get_gps_interface() {
+static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
     int err;
     hw_module_t* module;
-    const GpsInterface* interface = NULL;
 
-    err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
-    if (err == 0) {
-        hw_device_t* device;
-        err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
-        if (err == 0) {
-            gps_device_t* gps_device = (gps_device_t *)device;
-            interface = gps_device->get_gps_interface(gps_device);
-        }
-    }
-
-    return interface;
-}
-
-static const GpsInterface* GetGpsInterface(JNIEnv* env, jobject obj) {
-    // this must be set before calling into the HAL library
-    if (!mCallbacksObj)
-        mCallbacksObj = env->NewGlobalRef(obj);
-
-    if (!sGpsInterface) {
-        sGpsInterface = get_gps_interface();
-        if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) {
-            sGpsInterface = NULL;
-            return NULL;
-        }
-    }
-    return sGpsInterface;
-}
-
-static const AGpsInterface* GetAGpsInterface(JNIEnv* env, jobject obj)
-{
-    const GpsInterface* interface = GetGpsInterface(env, obj);
-    if (!interface)
-        return NULL;
-
-    if (!sAGpsInterface) {
-        sAGpsInterface = (const AGpsInterface*)interface->get_extension(AGPS_INTERFACE);
-        if (sAGpsInterface)
-            sAGpsInterface->init(&sAGpsCallbacks);
-    }
-    return sAGpsInterface;
-}
-
-static const GpsNiInterface* GetNiInterface(JNIEnv* env, jobject obj)
-{
-    const GpsInterface* interface = GetGpsInterface(env, obj);
-    if (!interface)
-        return NULL;
-
-    if (!sGpsNiInterface) {
-       sGpsNiInterface = (const GpsNiInterface*)interface->get_extension(GPS_NI_INTERFACE);
-        if (sGpsNiInterface)
-           sGpsNiInterface->init(&sGpsNiCallbacks);
-    }
-    return sGpsNiInterface;
-}
-
-static const AGpsRilInterface* GetAGpsRilInterface(JNIEnv* env, jobject obj)
-{
-    const GpsInterface* interface = GetGpsInterface(env, obj);
-    if (!interface)
-        return NULL;
-
-    if (!sAGpsRilInterface) {
-       sAGpsRilInterface = (const AGpsRilInterface*)interface->get_extension(AGPS_RIL_INTERFACE);
-        if (sAGpsRilInterface)
-            sAGpsRilInterface->init(&sAGpsRilCallbacks);
-    }
-    return sAGpsRilInterface;
-}
-
-static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
     method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
     method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
     method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
@@ -300,40 +228,73 @@
     method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
     method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
     method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
-    method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
+    method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
+            "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
     method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V");
     method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V");
+
+    err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
+    if (err == 0) {
+        hw_device_t* device;
+        err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
+        if (err == 0) {
+            gps_device_t* gps_device = (gps_device_t *)device;
+            sGpsInterface = gps_device->get_gps_interface(gps_device);
+        }
+    }
+    if (sGpsInterface) {
+        sGpsXtraInterface =
+            (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);
+        sAGpsInterface =
+            (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
+        sGpsNiInterface =
+            (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+        sGpsDebugInterface =
+            (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
+        sAGpsRilInterface =
+            (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
+    }
 }
 
 static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) {
-    return (sGpsInterface != NULL || get_gps_interface() != NULL);
+    return (sGpsInterface != NULL);
 }
 
 static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
 {
-    const GpsInterface* interface = GetGpsInterface(env, obj);
-    if (!interface)
+    // this must be set before calling into the HAL library
+    if (!mCallbacksObj)
+        mCallbacksObj = env->NewGlobalRef(obj);
+
+    // fail if the main interface fails to initialize
+    if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
         return false;
 
-    if (!sGpsDebugInterface)
-       sGpsDebugInterface = (const GpsDebugInterface*)interface->get_extension(GPS_DEBUG_INTERFACE);
+    // if XTRA initialization fails we will disable it by sGpsXtraInterface to null,
+    // but continue to allow the rest of the GPS interface to work.
+    if (sGpsXtraInterface && sGpsXtraInterface->init(&sGpsXtraCallbacks) != 0)
+        sGpsXtraInterface = NULL;
+    if (sAGpsInterface)
+        sAGpsInterface->init(&sAGpsCallbacks);
+    if (sGpsNiInterface)
+        sGpsNiInterface->init(&sGpsNiCallbacks);
+    if (sAGpsRilInterface)
+        sAGpsRilInterface->init(&sAGpsRilCallbacks);
 
     return true;
 }
 
 static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj)
 {
-    const GpsInterface* interface = GetGpsInterface(env, obj);
-    if (interface)
-        interface->cleanup();
+    if (sGpsInterface)
+        sGpsInterface->cleanup();
 }
 
 static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* env, jobject obj,
         jint mode, jint recurrence, jint min_interval, jint preferred_accuracy, jint preferred_time)
 {
-    const GpsInterface* interface = GetGpsInterface(env, obj);
-    if (interface)
-        return (interface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy,
+    if (sGpsInterface)
+        return (sGpsInterface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy,
                 preferred_time) == 0);
     else
         return false;
@@ -341,27 +302,24 @@
 
 static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj)
 {
-    const GpsInterface* interface = GetGpsInterface(env, obj);
-    if (interface)
-        return (interface->start() == 0);
+    if (sGpsInterface)
+        return (sGpsInterface->start() == 0);
     else
         return false;
 }
 
 static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj)
 {
-    const GpsInterface* interface = GetGpsInterface(env, obj);
-    if (interface)
-        return (interface->stop() == 0);
+    if (sGpsInterface)
+        return (sGpsInterface->stop() == 0);
     else
         return false;
 }
 
 static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags)
 {
-    const GpsInterface* interface = GetGpsInterface(env, obj);
-    if (interface)
-        interface->delete_aiding_data(flags);
+    if (sGpsInterface)
+        sGpsInterface->delete_aiding_data(flags);
 }
 
 static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj,
@@ -399,8 +357,8 @@
         jobject obj, jint type, jint mcc, jint mnc, jint lac, jint cid)
 {
     AGpsRefLocation location;
-    const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj);
-    if (!interface) {
+
+    if (!sAGpsRilInterface) {
         LOGE("no AGPS RIL interface in agps_set_reference_location_cellid");
         return;
     }
@@ -419,15 +377,15 @@
             return;
             break;
     }
-    interface->set_ref_location(&location, sizeof(location));
+    sAGpsRilInterface->set_ref_location(&location, sizeof(location));
 }
 
 static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* env,
         jobject obj, jbyteArray ni_msg, jint size)
 {
     size_t sz;
-    const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj);
-    if (!interface) {
+
+    if (!sAGpsRilInterface) {
         LOGE("no AGPS RIL interface in send_ni_message");
         return;
     }
@@ -435,21 +393,20 @@
         return;
     sz = (size_t)size;
     jbyte* b = env->GetByteArrayElements(ni_msg, 0);
-    interface->ni_message((uint8_t *)b,sz);
+    sAGpsRilInterface->ni_message((uint8_t *)b,sz);
     env->ReleaseByteArrayElements(ni_msg,b,0);
 }
 
 static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env,
         jobject obj, jint type, jstring  setid_string)
 {
-    const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj);
-    if (!interface) {
+    if (!sAGpsRilInterface) {
         LOGE("no AGPS RIL interface in agps_set_id");
         return;
     }
 
     const char *setid = env->GetStringUTFChars(setid_string, NULL);
-    interface->set_set_id(type, setid);
+    sAGpsRilInterface->set_set_id(type, setid);
     env->ReleaseStringUTFChars(setid_string, setid);
 }
 
@@ -469,40 +426,30 @@
 static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj,
         jlong time, jlong timeReference, jint uncertainty)
 {
-    const GpsInterface* interface = GetGpsInterface(env, obj);
-    if (interface)
-        interface->inject_time(time, timeReference, uncertainty);
+    if (sGpsInterface)
+        sGpsInterface->inject_time(time, timeReference, uncertainty);
 }
 
 static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jobject obj,
         jdouble latitude, jdouble longitude, jfloat accuracy)
 {
-    const GpsInterface* interface = GetGpsInterface(env, obj);
-    if (interface)
-        interface->inject_location(latitude, longitude, accuracy);
+    if (sGpsInterface)
+        sGpsInterface->inject_location(latitude, longitude, accuracy);
 }
 
 static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj)
 {
-    if (!sGpsXtraInterface) {
-        const GpsInterface* interface = GetGpsInterface(env, obj);
-        if (!interface)
-            return false;
-        sGpsXtraInterface = (const GpsXtraInterface*)interface->get_extension(GPS_XTRA_INTERFACE);
-        if (sGpsXtraInterface) {
-            int result = sGpsXtraInterface->init(&sGpsXtraCallbacks);
-            if (result) {
-                sGpsXtraInterface = NULL;
-            }
-        }
-    }
-
     return (sGpsXtraInterface != NULL);
 }
 
 static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj,
         jbyteArray data, jint length)
 {
+    if (!sGpsXtraInterface) {
+        LOGE("no XTRA interface in inject_xtra_data");
+        return;
+    }
+
     jbyte* bytes = (jbyte *)env->GetPrimitiveArrayCritical(data, 0);
     sGpsXtraInterface->inject_xtra_data((char *)bytes, length);
     env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
@@ -510,8 +457,7 @@
 
 static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn)
 {
-    const AGpsInterface* interface = GetAGpsInterface(env, obj);
-    if (!interface) {
+    if (!sAGpsInterface) {
         LOGE("no AGPS interface in agps_data_conn_open");
         return;
     }
@@ -520,53 +466,49 @@
         return;
     }
     const char *apnStr = env->GetStringUTFChars(apn, NULL);
-    interface->data_conn_open(apnStr);
+    sAGpsInterface->data_conn_open(apnStr);
     env->ReleaseStringUTFChars(apn, apnStr);
 }
 
 static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj)
 {
-    const AGpsInterface* interface = GetAGpsInterface(env, obj);
-    if (!interface) {
+    if (!sAGpsInterface) {
         LOGE("no AGPS interface in agps_data_conn_open");
         return;
     }
-    interface->data_conn_closed();
+    sAGpsInterface->data_conn_closed();
 }
 
 static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj)
 {
-    const AGpsInterface* interface = GetAGpsInterface(env, obj);
-    if (!interface) {
+    if (!sAGpsInterface) {
         LOGE("no AGPS interface in agps_data_conn_open");
         return;
     }
-    interface->data_conn_failed();
+    sAGpsInterface->data_conn_failed();
 }
 
 static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj,
         jint type, jstring hostname, jint port)
 {
-    const AGpsInterface* interface = GetAGpsInterface(env, obj);
-    if (!interface) {
+    if (!sAGpsInterface) {
         LOGE("no AGPS interface in agps_data_conn_open");
         return;
     }
     const char *c_hostname = env->GetStringUTFChars(hostname, NULL);
-    interface->set_server(type, c_hostname, port);
+    sAGpsInterface->set_server(type, c_hostname, port);
     env->ReleaseStringUTFChars(hostname, c_hostname);
 }
 
 static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj,
       jint notifId, jint response)
 {
-    const GpsNiInterface* interface = GetNiInterface(env, obj);
-    if (!interface) {
+    if (!sGpsNiInterface) {
         LOGE("no NI interface in send_ni_response");
         return;
     }
 
-    interface->respond(notifId, response);
+    sGpsNiInterface->respond(notifId, response);
 }
 
 static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj)
@@ -586,14 +528,14 @@
 static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject obj,
         jboolean connected, int type, jboolean roaming, jstring extraInfo)
 {
-    const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj);
-    if (interface && interface->update_network_state) {
+
+    if (sAGpsRilInterface && sAGpsRilInterface->update_network_state) {
         if (extraInfo) {
             const char *extraInfoStr = env->GetStringUTFChars(extraInfo, NULL);
-            interface->update_network_state(connected, type, roaming, extraInfoStr);
+            sAGpsRilInterface->update_network_state(connected, type, roaming, extraInfoStr);
             env->ReleaseStringUTFChars(extraInfo, extraInfoStr);
         } else {
-            interface->update_network_state(connected, type, roaming, NULL);
+            sAGpsRilInterface->update_network_state(connected, type, roaming, NULL);
         }
     }
 }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 0f7d639..57af001 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -341,6 +341,45 @@
     drawWithOpenGL(clip, tex);
 }
 
+// As documented in libhardware header, formats in the range
+// 0x100 - 0x1FF are specific to the HAL implementation, and
+// are known to have no alpha channel
+// TODO: move definition for device-specific range into
+// hardware.h, instead of using hard-coded values here.
+#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
+
+bool Layer::needsBlending(const sp<GraphicBuffer>& buffer) const
+{
+    // If buffers where set with eOpaque flag, all buffers are known to
+    // be opaque without having to check their actual format
+    if (mNeedsBlending && buffer != NULL) {
+        PixelFormat format = buffer->getPixelFormat();
+
+        if (HARDWARE_IS_DEVICE_FORMAT(format)) {
+            return false;
+        }
+
+        PixelFormatInfo info;
+        status_t err = getPixelFormatInfo(format, &info);
+        if (!err && info.h_alpha <= info.l_alpha) {
+            return false;
+        }
+    }
+
+    // Return opacity as determined from flags and format options
+    // passed to setBuffers()
+    return mNeedsBlending;
+}
+
+bool Layer::needsBlending() const
+{
+    if (mBufferManager.hasActiveBuffer()) {
+        return needsBlending(mBufferManager.getActiveBuffer());
+    }
+
+    return mNeedsBlending;
+}
+
 bool Layer::needsFiltering() const
 {
     if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
@@ -588,6 +627,9 @@
     // we retired a buffer, which becomes the new front buffer
 
     const bool noActiveBuffer = !mBufferManager.hasActiveBuffer();
+    const bool activeBlending =
+            noActiveBuffer ? true : needsBlending(mBufferManager.getActiveBuffer());
+
     if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) {
         LOGE("retireAndLock() buffer index (%d) out of range", int(buf));
         mPostedDirtyRegion.clear();
@@ -602,6 +644,12 @@
 
     sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
     if (newFrontBuffer != NULL) {
+        if (!noActiveBuffer && activeBlending != needsBlending(newFrontBuffer)) {
+            // new buffer has different opacity than previous active buffer, need
+            // to recompute visible regions accordingly
+            recomputeVisibleRegions = true;
+        }
+
         // get the dirty region
         // compute the posted region
         const Region dirty(lcblk->getDirtyRegion(buf));
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2b38414..bccc900 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -75,7 +75,8 @@
     virtual uint32_t doTransaction(uint32_t transactionFlags);
     virtual void lockPageFlip(bool& recomputeVisibleRegions);
     virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
-    virtual bool needsBlending() const      { return mNeedsBlending; }
+    virtual bool needsBlending(const sp<GraphicBuffer>& buffer) const;
+    virtual bool needsBlending() const;
     virtual bool needsDithering() const     { return mNeedsDithering; }
     virtual bool needsFiltering() const;
     virtual bool isSecure() const           { return mSecure; }
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index 21e9e44..ad21a18 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -1178,6 +1178,21 @@
         Message response);
 
     /**
+     * (AsyncResult)response.obj).result will be an Integer representing
+     * the sum of enabled service classes (sum of SERVICE_CLASS_*) for the
+     * application with appId.
+     *
+     * @param facility one of CB_FACILTY_*
+     * @param password password or "" if not required
+     * @param serviceClass is a sum of SERVICE_CLASS_*
+     * @param appId is application Id or null if none
+     * @param response is callback message
+     */
+
+    void queryFacilityLockForApp(String facility, String password, int serviceClass, String appId,
+        Message response);
+
+    /**
      * @param facility one of CB_FACILTY_*
      * @param lockState true means lock, false means unlock
      * @param password password or "" if not required
@@ -1187,6 +1202,18 @@
     void setFacilityLock (String facility, boolean lockState, String password,
         int serviceClass, Message response);
 
+    /**
+     * Set the facility lock for the app with this AID on the ICC card.
+     *
+     * @param facility one of CB_FACILTY_*
+     * @param lockState true means lock, false means unlock
+     * @param password password or "" if not required
+     * @param serviceClass is a sum of SERVICE_CLASS_*
+     * @param appId is application Id or null if none
+     * @param response is callback message
+     */
+    void setFacilityLockForApp(String facility, boolean lockState, String password,
+        int serviceClass, String appId, Message response);
 
     void sendUSSD (String ussdString, Message response);
 
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 76c6229..bccb219 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1643,30 +1643,18 @@
         send(rr);
     }
 
+    @Override
     public void
-    queryFacilityLock (String facility, String password, int serviceClass,
+    queryFacilityLock(String facility, String password, int serviceClass,
                             Message response) {
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_FACILITY_LOCK, response);
-
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
-        // count strings
-        rr.mp.writeInt(3);
-
-        rr.mp.writeString(facility);
-        rr.mp.writeString(password);
-
-        rr.mp.writeString(Integer.toString(serviceClass));
-
-        send(rr);
+        queryFacilityLockForApp(facility, password, serviceClass, null, response);
     }
 
+    @Override
     public void
-    setFacilityLock (String facility, boolean lockState, String password,
-                        int serviceClass, Message response) {
-        String lockString;
-         RILRequest rr
-                = RILRequest.obtain(RIL_REQUEST_SET_FACILITY_LOCK, response);
+    queryFacilityLockForApp(String facility, String password, int serviceClass, String appId,
+                            Message response) {
+        RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_FACILITY_LOCK, response);
 
         if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
 
@@ -1674,10 +1662,40 @@
         rr.mp.writeInt(4);
 
         rr.mp.writeString(facility);
+        rr.mp.writeString(password);
+
+        rr.mp.writeString(Integer.toString(serviceClass));
+        rr.mp.writeString(appId);
+
+        send(rr);
+    }
+
+    @Override
+    public void
+    setFacilityLock (String facility, boolean lockState, String password,
+                        int serviceClass, Message response) {
+        setFacilityLockForApp(facility, lockState, password, serviceClass, null, response);
+    }
+
+    @Override
+    public void
+    setFacilityLockForApp(String facility, boolean lockState, String password,
+                        int serviceClass, String appId, Message response) {
+        String lockString;
+         RILRequest rr
+                = RILRequest.obtain(RIL_REQUEST_SET_FACILITY_LOCK, response);
+
+        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+        // count strings
+        rr.mp.writeInt(5);
+
+        rr.mp.writeString(facility);
         lockString = (lockState)?"1":"0";
         rr.mp.writeString(lockString);
         rr.mp.writeString(password);
         rr.mp.writeString(Integer.toString(serviceClass));
+        rr.mp.writeString(appId);
 
         send(rr);
 
diff --git a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
index b6c3b67..f2ece7f 100644
--- a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -251,14 +251,26 @@
     public void getBasebandVersion (Message response) {
     }
 
-    public void queryFacilityLock (String facility, String password,
+    @Override
+    public void queryFacilityLock(String facility, String password,
             int serviceClass, Message response) {
     }
 
-    public void setFacilityLock (String facility, boolean lockState,
+    @Override
+    public void queryFacilityLockForApp(String facility, String password,
+            int serviceClass, String appId, Message response) {
+    }
+
+    @Override
+    public void setFacilityLock(String facility, boolean lockState,
             String password, int serviceClass, Message response) {
     }
 
+    @Override
+    public void setFacilityLockForApp(String facility, boolean lockState,
+            String password, int serviceClass, String appId, Message response) {
+    }
+
     public void sendUSSD (String ussdString, Message response) {
     }
 
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index 242d44f..d9bd7e8 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -331,35 +331,31 @@
         mSsnNotifyOn = enable;
     }
 
-    /**
-     * (AsyncResult)response.obj).result will be an Integer representing
-     * the sum of enabled service classes (sum of SERVICE_CLASS_*)
-     *
-     * @param facility one of CB_FACILTY_*
-     * @param pin password or "" if not required
-     * @param serviceClass is a sum of SERVICE_CLASS_*
-     */
-
-    public void queryFacilityLock (String facility, String pin,
+    @Override
+    public void queryFacilityLock(String facility, String pin,
                                    int serviceClass, Message result) {
-        if (facility != null &&
-                facility.equals(CommandsInterface.CB_FACILITY_BA_SIM)) {
+        queryFacilityLockForApp(facility, pin, serviceClass, null, result);
+    }
+
+    @Override
+    public void queryFacilityLockForApp(String facility, String pin, int serviceClass,
+            String appId, Message result) {
+        if (facility != null && facility.equals(CommandsInterface.CB_FACILITY_BA_SIM)) {
             if (result != null) {
                 int[] r = new int[1];
                 r[0] = (mSimLockEnabled ? 1 : 0);
-                Log.i(LOG_TAG, "[SimCmd] queryFacilityLock: SIM is " +
-                        (r[0] == 0 ? "unlocked" : "locked"));
+                Log.i(LOG_TAG, "[SimCmd] queryFacilityLock: SIM is "
+                        + (r[0] == 0 ? "unlocked" : "locked"));
                 AsyncResult.forMessage(result, r, null);
                 result.sendToTarget();
             }
             return;
-        } else if (facility != null &&
-                facility.equals(CommandsInterface.CB_FACILITY_BA_FD)) {
+        } else if (facility != null && facility.equals(CommandsInterface.CB_FACILITY_BA_FD)) {
             if (result != null) {
                 int[] r = new int[1];
                 r[0] = (mSimFdnEnabled ? 1 : 0);
-                Log.i(LOG_TAG, "[SimCmd] queryFacilityLock: FDN is " +
-                        (r[0] == 0 ? "disabled" : "enabled"));
+                Log.i(LOG_TAG, "[SimCmd] queryFacilityLock: FDN is "
+                        + (r[0] == 0 ? "disabled" : "enabled"));
                 AsyncResult.forMessage(result, r, null);
                 result.sendToTarget();
             }
@@ -369,14 +365,15 @@
         unimplemented(result);
     }
 
-    /**
-     * @param facility one of CB_FACILTY_*
-     * @param lockEnabled true if SIM lock is enabled
-     * @param pin the SIM pin or "" if not required
-     * @param serviceClass is a sum of SERVICE_CLASS_*
-     */
-    public void setFacilityLock (String facility, boolean lockEnabled,
-                                 String pin, int serviceClass,
+    @Override
+    public void setFacilityLock(String facility, boolean lockEnabled, String pin, int serviceClass,
+            Message result) {
+        setFacilityLockForApp(facility, lockEnabled, pin, serviceClass, null, result);
+    }
+
+    @Override
+    public void setFacilityLockForApp(String facility, boolean lockEnabled,
+                                 String pin, int serviceClass, String appId,
                                  Message result) {
         if (facility != null &&
                 facility.equals(CommandsInterface.CB_FACILITY_BA_SIM)) {
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index ae7ec45..e82f9aa 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -397,6 +397,16 @@
         </activity>
 
         <activity
+                android:name="Animated3dActivity"
+                android:label="_Animated 3d"
+                android:theme="@android:style/Theme.Translucent.NoTitleBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="SimplePathsActivity"
                 android:label="_SimplePaths">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/large_photo.jpg b/tests/HwAccelerationTest/res/drawable-nodpi/large_photo.jpg
new file mode 100644
index 0000000..e23dbb0
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable-nodpi/large_photo.jpg
Binary files differ
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Animated3dActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/Animated3dActivity.java
new file mode 100644
index 0000000..f632c83
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/Animated3dActivity.java
@@ -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.
+ */
+
+package com.android.test.hwui;
+
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Camera;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class Animated3dActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        ImageView view = new ImageView(this);
+        view.setImageResource(R.drawable.large_photo);
+
+        setContentView(view, new FrameLayout.LayoutParams(
+                FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT
+        ));
+
+        ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 0.0f, 360.0f);
+        animator.setDuration(4000);
+        animator.setRepeatCount(ObjectAnimator.INFINITE);
+        animator.setRepeatMode(ObjectAnimator.REVERSE);
+        animator.start();
+    }
+}
diff --git a/tests/RenderScriptTests/Android.mk b/tests/RenderScriptTests/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/tests/RenderScriptTests/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/libs/rs/java/ImageProcessing/Android.mk b/tests/RenderScriptTests/ImageProcessing/Android.mk
similarity index 100%
rename from libs/rs/java/ImageProcessing/Android.mk
rename to tests/RenderScriptTests/ImageProcessing/Android.mk
diff --git a/libs/rs/java/ImageProcessing/AndroidManifest.xml b/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml
similarity index 100%
rename from libs/rs/java/ImageProcessing/AndroidManifest.xml
rename to tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml
diff --git a/libs/rs/java/ImageProcessing/res/drawable-hdpi/data.jpg b/tests/RenderScriptTests/ImageProcessing/res/drawable-hdpi/data.jpg
similarity index 100%
rename from libs/rs/java/ImageProcessing/res/drawable-hdpi/data.jpg
rename to tests/RenderScriptTests/ImageProcessing/res/drawable-hdpi/data.jpg
Binary files differ
diff --git a/libs/rs/java/ImageProcessing/res/drawable/data.jpg b/tests/RenderScriptTests/ImageProcessing/res/drawable/data.jpg
similarity index 100%
rename from libs/rs/java/ImageProcessing/res/drawable/data.jpg
rename to tests/RenderScriptTests/ImageProcessing/res/drawable/data.jpg
Binary files differ
diff --git a/libs/rs/java/ImageProcessing/res/layout/main.xml b/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
similarity index 100%
rename from libs/rs/java/ImageProcessing/res/layout/main.xml
rename to tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
diff --git a/libs/rs/java/ImageProcessing/res/values/strings.xml b/tests/RenderScriptTests/ImageProcessing/res/values/strings.xml
similarity index 100%
rename from libs/rs/java/ImageProcessing/res/values/strings.xml
rename to tests/RenderScriptTests/ImageProcessing/res/values/strings.xml
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
similarity index 100%
rename from libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
rename to tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
similarity index 100%
rename from libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
rename to tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ip.rsh b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ip.rsh
similarity index 100%
rename from libs/rs/java/ImageProcessing/src/com/android/rs/image/ip.rsh
rename to tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ip.rsh
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs
similarity index 100%
rename from libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs
rename to tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
similarity index 100%
rename from libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
rename to tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
diff --git a/libs/rs/java/ModelViewer/Android.mk b/tests/RenderScriptTests/ModelViewer/Android.mk
similarity index 100%
rename from libs/rs/java/ModelViewer/Android.mk
rename to tests/RenderScriptTests/ModelViewer/Android.mk
diff --git a/libs/rs/java/ModelViewer/AndroidManifest.xml b/tests/RenderScriptTests/ModelViewer/AndroidManifest.xml
similarity index 100%
rename from libs/rs/java/ModelViewer/AndroidManifest.xml
rename to tests/RenderScriptTests/ModelViewer/AndroidManifest.xml
diff --git a/libs/rs/java/ModelViewer/res/drawable/robot.png b/tests/RenderScriptTests/ModelViewer/res/drawable/robot.png
similarity index 100%
rename from libs/rs/java/ModelViewer/res/drawable/robot.png
rename to tests/RenderScriptTests/ModelViewer/res/drawable/robot.png
Binary files differ
diff --git a/libs/rs/java/ModelViewer/res/menu/loader_menu.xml b/tests/RenderScriptTests/ModelViewer/res/menu/loader_menu.xml
similarity index 100%
rename from libs/rs/java/ModelViewer/res/menu/loader_menu.xml
rename to tests/RenderScriptTests/ModelViewer/res/menu/loader_menu.xml
diff --git a/libs/rs/java/ModelViewer/res/raw/robot.a3d b/tests/RenderScriptTests/ModelViewer/res/raw/robot.a3d
similarity index 100%
rename from libs/rs/java/ModelViewer/res/raw/robot.a3d
rename to tests/RenderScriptTests/ModelViewer/res/raw/robot.a3d
Binary files differ
diff --git a/libs/rs/java/ModelViewer/res/values/strings.xml b/tests/RenderScriptTests/ModelViewer/res/values/strings.xml
similarity index 100%
rename from libs/rs/java/ModelViewer/res/values/strings.xml
rename to tests/RenderScriptTests/ModelViewer/res/values/strings.xml
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/A3DSelector.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/A3DSelector.java
similarity index 100%
rename from libs/rs/java/ModelViewer/src/com/android/modelviewer/A3DSelector.java
rename to tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/A3DSelector.java
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraph.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraph.java
similarity index 100%
rename from libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraph.java
rename to tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraph.java
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
similarity index 100%
rename from libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
rename to tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphView.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphView.java
similarity index 100%
rename from libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphView.java
rename to tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphView.java
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SgTransform.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SgTransform.java
similarity index 100%
rename from libs/rs/java/ModelViewer/src/com/android/modelviewer/SgTransform.java
rename to tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SgTransform.java
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModel.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModel.java
similarity index 100%
rename from libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModel.java
rename to tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModel.java
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
similarity index 100%
rename from libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
rename to tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelView.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelView.java
similarity index 100%
rename from libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelView.java
rename to tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelView.java
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/scenegraph.rs
similarity index 100%
rename from libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
rename to tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/scenegraph.rs
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
similarity index 99%
rename from libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs
rename to tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
index 1034b85..4c38745 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs
+++ b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
@@ -157,5 +157,5 @@
 
     drawDescription();
 
-    return 10;
+    return 0;
 }
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform.rs
similarity index 100%
rename from libs/rs/java/ModelViewer/src/com/android/modelviewer/transform.rs
rename to tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform.rs
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform_def.rsh b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform_def.rsh
similarity index 100%
rename from libs/rs/java/ModelViewer/src/com/android/modelviewer/transform_def.rsh
rename to tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform_def.rsh
diff --git a/tests/RenderScriptTests/PerfTest/Android.mk b/tests/RenderScriptTests/PerfTest/Android.mk
new file mode 100644
index 0000000..85b0a65
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/Android.mk
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := PerfTest
+
+include $(BUILD_PACKAGE)
+
+endif
diff --git a/tests/RenderScriptTests/PerfTest/AndroidManifest.xml b/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
new file mode 100644
index 0000000..3afb3b2
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.perftest">
+    <uses-sdk android:minSdkVersion="11" />
+    <application android:label="PerfTest"
+    android:icon="@drawable/test_pattern">
+        <activity android:name="RsBench"
+                  android:label="RsBenchmark"
+                  android:theme="@android:style/Theme.Black.NoTitleBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable/checker.png b/tests/RenderScriptTests/PerfTest/res/drawable/checker.png
new file mode 100644
index 0000000..b631e1e
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/drawable/checker.png
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable/data.png b/tests/RenderScriptTests/PerfTest/res/drawable/data.png
new file mode 100644
index 0000000..8e34714
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/drawable/data.png
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable/leaf.png b/tests/RenderScriptTests/PerfTest/res/drawable/leaf.png
new file mode 100644
index 0000000..3cd3775
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/drawable/leaf.png
Binary files differ
diff --git a/libs/rs/java/tests/res/drawable/test_pattern.png b/tests/RenderScriptTests/PerfTest/res/drawable/test_pattern.png
similarity index 100%
copy from libs/rs/java/tests/res/drawable/test_pattern.png
copy to tests/RenderScriptTests/PerfTest/res/drawable/test_pattern.png
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable/torusmap.png b/tests/RenderScriptTests/PerfTest/res/drawable/torusmap.png
new file mode 100644
index 0000000..1e08f3b
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/drawable/torusmap.png
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/multitexf.glsl b/tests/RenderScriptTests/PerfTest/res/raw/multitexf.glsl
new file mode 100644
index 0000000..e492a47
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/raw/multitexf.glsl
@@ -0,0 +1,13 @@
+varying vec2 varTex0;
+
+void main() {
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col0 = texture2D(UNI_Tex0, t0).rgba;
+   lowp vec4 col1 = texture2D(UNI_Tex1, t0*4.0).rgba;
+   lowp vec4 col2 = texture2D(UNI_Tex2, t0).rgba;
+   col0.xyz = col0.xyz*col1.xyz*1.5;
+   col0.xyz = mix(col0.xyz, col2.xyz, col2.w);
+   col0.w = 0.5;
+   gl_FragColor = col0;
+}
+
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/shader2f.glsl b/tests/RenderScriptTests/PerfTest/res/raw/shader2f.glsl
new file mode 100644
index 0000000..5fc05f1
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/raw/shader2f.glsl
@@ -0,0 +1,29 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+   vec3 V = normalize(-varWorldPos.xyz);
+   vec3 worldNorm = normalize(varWorldNormal);
+
+   vec3 light0Vec = normalize(UNI_light0_Posision.xyz - varWorldPos);
+   vec3 light0R = -reflect(light0Vec, worldNorm);
+   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light0_Diffuse;
+   float light0Spec = clamp(dot(light0R, V), 0.001, 1.0);
+   float light0_Specular = pow(light0Spec, UNI_light0_CosinePower) * UNI_light0_Specular;
+
+   vec3 light1Vec = normalize(UNI_light1_Posision.xyz - varWorldPos);
+   vec3 light1R = reflect(light1Vec, worldNorm);
+   float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light1_Diffuse;
+   float light1Spec = clamp(dot(light1R, V), 0.001, 1.0);
+   float light1_Specular = pow(light1Spec, UNI_light1_CosinePower) * UNI_light1_Specular;
+
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+   col.xyz = col.xyz * (light0_Diffuse * UNI_light0_DiffuseColor.xyz + light1_Diffuse * UNI_light1_DiffuseColor.xyz);
+   col.xyz += light0_Specular * UNI_light0_SpecularColor.xyz;
+   col.xyz += light1_Specular * UNI_light1_SpecularColor.xyz;
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/shader2movev.glsl b/tests/RenderScriptTests/PerfTest/res/raw/shader2movev.glsl
new file mode 100644
index 0000000..a2c807e
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/raw/shader2movev.glsl
@@ -0,0 +1,21 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+// This is where actual shader code begins
+void main() {
+   vec4 objPos = ATTRIB_position;
+   vec3 oldPos = objPos.xyz;
+   objPos.xyz += 0.1*sin(objPos.xyz*2.0 + UNI_time);
+   objPos.xyz += 0.05*sin(objPos.xyz*4.0 + UNI_time*0.5);
+   objPos.xyz += 0.02*sin(objPos.xyz*7.0 + UNI_time*0.75);
+   vec4 worldPos = UNI_model * objPos;
+   gl_Position = UNI_proj * worldPos;
+
+   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
+   vec3 worldNorm = model3 * (ATTRIB_normal + oldPos - objPos.xyz);
+
+   varWorldPos = worldPos.xyz;
+   varWorldNormal = worldNorm;
+   varTex0 = ATTRIB_texture0;
+}
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/shader2v.glsl b/tests/RenderScriptTests/PerfTest/res/raw/shader2v.glsl
new file mode 100644
index 0000000..e6885a3
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/raw/shader2v.glsl
@@ -0,0 +1,17 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+// This is where actual shader code begins
+void main() {
+   vec4 objPos = ATTRIB_position;
+   vec4 worldPos = UNI_model * objPos;
+   gl_Position = UNI_proj * worldPos;
+
+   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
+   vec3 worldNorm = model3 * ATTRIB_normal;
+
+   varWorldPos = worldPos.xyz;
+   varWorldNormal = worldNorm;
+   varTex0 = ATTRIB_texture0;
+}
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/shaderf.glsl b/tests/RenderScriptTests/PerfTest/res/raw/shaderf.glsl
new file mode 100644
index 0000000..d56e203
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/raw/shaderf.glsl
@@ -0,0 +1,16 @@
+
+varying lowp float light0_Diffuse;
+varying lowp float light0_Specular;
+varying lowp float light1_Diffuse;
+varying lowp float light1_Specular;
+varying vec2 varTex0;
+
+void main() {
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+   col.xyz = col.xyz * (light0_Diffuse * UNI_light0_DiffuseColor.xyz + light1_Diffuse * UNI_light1_DiffuseColor.xyz);
+   col.xyz += light0_Specular * UNI_light0_SpecularColor.xyz;
+   col.xyz += light1_Specular * UNI_light1_SpecularColor.xyz;
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/shaderv.glsl b/tests/RenderScriptTests/PerfTest/res/raw/shaderv.glsl
new file mode 100644
index 0000000..f7d01de
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/raw/shaderv.glsl
@@ -0,0 +1,30 @@
+varying float light0_Diffuse;
+varying float light0_Specular;
+varying float light1_Diffuse;
+varying float light1_Specular;
+varying vec2 varTex0;
+
+// This is where actual shader code begins
+void main() {
+   vec4 worldPos = UNI_model * ATTRIB_position;
+   gl_Position = UNI_proj * worldPos;
+
+   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
+   vec3 worldNorm = model3 * ATTRIB_normal;
+   vec3 V = normalize(-worldPos.xyz);
+
+   vec3 light0Vec = normalize(UNI_light0_Posision.xyz - worldPos.xyz);
+   vec3 light0R = -reflect(light0Vec, worldNorm);
+   light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light0_Diffuse;
+   float light0Spec = clamp(dot(light0R, V), 0.001, 1.0);
+   light0_Specular = pow(light0Spec, UNI_light0_CosinePower) * UNI_light0_Specular;
+
+   vec3 light1Vec = normalize(UNI_light1_Posision.xyz - worldPos.xyz);
+   vec3 light1R = reflect(light1Vec, worldNorm);
+   light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light1_Diffuse;
+   float light1Spec = clamp(dot(light1R, V), 0.001, 1.0);
+   light1_Specular = pow(light1Spec, UNI_light1_CosinePower) * UNI_light1_Specular;
+
+   gl_PointSize = 1.0;
+   varTex0 = ATTRIB_texture0;
+}
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/torus.a3d b/tests/RenderScriptTests/PerfTest/res/raw/torus.a3d
new file mode 100644
index 0000000..0322b01
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/raw/torus.a3d
Binary files differ
diff --git a/libs/rs/java/Samples/src/com/android/samples/RsBench.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
similarity index 98%
rename from libs/rs/java/Samples/src/com/android/samples/RsBench.java
rename to tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
index a29dddc..cfe1970 100644
--- a/libs/rs/java/Samples/src/com/android/samples/RsBench.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.samples;
+package com.android.perftest;
 
 import android.renderscript.RSSurfaceView;
 import android.renderscript.RenderScript;
diff --git a/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
similarity index 93%
rename from libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java
rename to tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
index 1afcee3..9757ec6 100644
--- a/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.samples;
+package com.android.perftest;
 
 import java.io.Writer;
 
@@ -84,9 +84,6 @@
     private ScriptField_VertexShaderConstants3_s mVSConstPixel;
     private ScriptField_FragentShaderConstants3_s mFSConstPixel;
 
-    private ProgramVertex mProgVertexCube;
-    private ProgramFragment mProgFragmentCube;
-
     private ProgramRaster mCullBack;
     private ProgramRaster mCullFront;
     private ProgramRaster mCullNone;
@@ -95,7 +92,6 @@
     private Allocation mTexOpaque;
     private Allocation mTexTransparent;
     private Allocation mTexChecker;
-    private Allocation mTexCube;
 
     private Mesh m10by10Mesh;
     private Mesh m100by100Mesh;
@@ -247,19 +243,6 @@
         // Bind the source of constant data
         mProgFragmentCustom.bindConstants(mFSConst.getAllocation(), 0);
 
-        // Cubemap test shaders
-        pvbCustom = new ProgramVertex.Builder(mRS);
-        pvbCustom.setShader(mRes, R.raw.shadercubev);
-        pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS));
-        pvbCustom.addConstant(mVSConst.getAllocation().getType());
-        mProgVertexCube = pvbCustom.create();
-        mProgVertexCube.bindConstants(mVSConst.getAllocation(), 0);
-
-        pfbCustom = new ProgramFragment.Builder(mRS);
-        pfbCustom.setShader(mRes, R.raw.shadercubef);
-        pfbCustom.addTexture(Program.TextureType.TEXTURE_CUBE);
-        mProgFragmentCube = pfbCustom.create();
-
         pvbCustom = new ProgramVertex.Builder(mRS);
         pvbCustom.setShader(mRes, R.raw.shader2v);
         pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS));
@@ -290,8 +273,6 @@
 
         mScript.set_gProgVertexCustom(mProgVertexCustom);
         mScript.set_gProgFragmentCustom(mProgFragmentCustom);
-        mScript.set_gProgVertexCube(mProgVertexCube);
-        mScript.set_gProgFragmentCube(mProgFragmentCube);
         mScript.set_gProgVertexPixelLight(mProgVertexPixelLight);
         mScript.set_gProgVertexPixelLightMove(mProgVertexPixelLightMove);
         mScript.set_gProgFragmentPixelLight(mProgFragmentPixelLight);
@@ -316,14 +297,11 @@
         mTexOpaque = loadTextureRGB(R.drawable.data);
         mTexTransparent = loadTextureARGB(R.drawable.leaf);
         mTexChecker = loadTextureRGB(R.drawable.checker);
-        Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.cubemap_test);
-        mTexCube = Allocation.createCubemapFromBitmap(mRS, b);
 
         mScript.set_gTexTorus(mTexTorus);
         mScript.set_gTexOpaque(mTexOpaque);
         mScript.set_gTexTransparent(mTexTransparent);
         mScript.set_gTexChecker(mTexChecker);
-        mScript.set_gTexCube(mTexCube);
     }
 
     private void initFonts() {
diff --git a/libs/rs/java/Samples/src/com/android/samples/RsBenchView.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
similarity index 98%
rename from libs/rs/java/Samples/src/com/android/samples/RsBenchView.java
rename to tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
index 0a56668..ee7e508 100644
--- a/libs/rs/java/Samples/src/com/android/samples/RsBenchView.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.samples;
+package com.android.perftest;
 
 import java.io.Writer;
 import java.util.ArrayList;
diff --git a/libs/rs/java/Samples/src/com/android/samples/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
similarity index 98%
rename from libs/rs/java/Samples/src/com/android/samples/rsbench.rs
rename to tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
index a1368e6..3c92725 100644
--- a/libs/rs/java/Samples/src/com/android/samples/rsbench.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
@@ -14,7 +14,7 @@
 
 #pragma version(1)
 
-#pragma rs java_package_name(com.android.samples)
+#pragma rs java_package_name(com.android.perftest)
 
 #include "rs_graphics.rsh"
 #include "shader_def.rsh"
@@ -34,7 +34,6 @@
 rs_allocation gTexTorus;
 rs_allocation gTexTransparent;
 rs_allocation gTexChecker;
-rs_allocation gTexCube;
 
 rs_mesh g10by10Mesh;
 rs_mesh g100by100Mesh;
@@ -75,8 +74,6 @@
 rs_program_vertex gProgVertexPixelLight;
 rs_program_vertex gProgVertexPixelLightMove;
 rs_program_fragment gProgFragmentPixelLight;
-rs_program_vertex gProgVertexCube;
-rs_program_fragment gProgFragmentCube;
 rs_program_fragment gProgFragmentMultitex;
 
 float gDt = 0;
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/shader_def.rsh b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/shader_def.rsh
new file mode 100644
index 0000000..1d77ea9
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/shader_def.rsh
@@ -0,0 +1,83 @@
+// 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.perftest)
+
+typedef struct VertexShaderConstants_s {
+    rs_matrix4x4 model;
+    rs_matrix4x4 proj;
+    float4 light0_Posision;
+    float light0_Diffuse;
+    float light0_Specular;
+    float light0_CosinePower;
+
+    float4 light1_Posision;
+    float light1_Diffuse;
+    float light1_Specular;
+    float light1_CosinePower;
+} VertexShaderConstants;
+
+typedef struct VertexShaderConstants2_s {
+    rs_matrix4x4 model[2];
+    rs_matrix4x4 proj;
+    float4 light_Posision[2];
+    float light_Diffuse[2];
+    float light_Specular[2];
+    float light_CosinePower[2];
+} VertexShaderConstants2;
+
+typedef struct VertexShaderConstants3_s {
+    rs_matrix4x4 model;
+    rs_matrix4x4 proj;
+    float time;
+} VertexShaderConstants3;
+
+
+typedef struct FragentShaderConstants_s {
+    float4 light0_DiffuseColor;
+    float4 light0_SpecularColor;
+
+    float4 light1_DiffuseColor;
+    float4 light1_SpecularColor;
+} FragentShaderConstants;
+
+typedef struct FragentShaderConstants2_s {
+    float4 light_DiffuseColor[2];
+    float4 light_SpecularColor[2];
+} FragentShaderConstants2;
+
+typedef struct FragentShaderConstants3_s {
+    float4 light0_DiffuseColor;
+    float4 light0_SpecularColor;
+    float4 light0_Posision;
+    float light0_Diffuse;
+    float light0_Specular;
+    float light0_CosinePower;
+
+    float4 light1_DiffuseColor;
+    float4 light1_SpecularColor;
+    float4 light1_Posision;
+    float light1_Diffuse;
+    float light1_Specular;
+    float light1_CosinePower;
+} FragentShaderConstants3;
+
+typedef struct VertexShaderInputs_s {
+    float4 position;
+    float3 normal;
+    float2 texture0;
+} VertexShaderInputs;
+
diff --git a/libs/rs/java/tests/Android.mk b/tests/RenderScriptTests/tests/Android.mk
similarity index 100%
rename from libs/rs/java/tests/Android.mk
rename to tests/RenderScriptTests/tests/Android.mk
diff --git a/libs/rs/java/tests/AndroidManifest.xml b/tests/RenderScriptTests/tests/AndroidManifest.xml
similarity index 100%
rename from libs/rs/java/tests/AndroidManifest.xml
rename to tests/RenderScriptTests/tests/AndroidManifest.xml
diff --git a/libs/rs/java/tests/res/drawable/test_pattern.png b/tests/RenderScriptTests/tests/res/drawable/test_pattern.png
similarity index 100%
rename from libs/rs/java/tests/res/drawable/test_pattern.png
rename to tests/RenderScriptTests/tests/res/drawable/test_pattern.png
Binary files differ
diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTest.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTest.java
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/RSTest.java
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/RSTest.java
diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestView.java
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/RSTestView.java
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestView.java
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_fp_mad.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_fp_mad.java
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/UT_fp_mad.java
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/UT_fp_mad.java
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_math.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_math.java
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/UT_math.java
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/UT_math.java
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_rsdebug.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rsdebug.java
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/UT_rsdebug.java
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rsdebug.java
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_rstime.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rstime.java
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/UT_rstime.java
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rstime.java
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_rstypes.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rstypes.java
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/UT_rstypes.java
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rstypes.java
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/UnitTest.java
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
diff --git a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/fp_mad.rs
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/fp_mad.rs
diff --git a/libs/rs/java/tests/src/com/android/rs/test/math.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/math.rs
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/math.rs
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/math.rs
diff --git a/libs/rs/java/tests/src/com/android/rs/test/primitives.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/primitives.rs
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/primitives.rs
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/primitives.rs
diff --git a/libs/rs/java/tests/src/com/android/rs/test/rsdebug.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/rsdebug.rs
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/rsdebug.rs
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/rsdebug.rs
diff --git a/libs/rs/java/tests/src/com/android/rs/test/rslist.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/rslist.rs
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs
diff --git a/libs/rs/java/tests/src/com/android/rs/test/rstime.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/rstime.rs
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/rstime.rs
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/rstime.rs
diff --git a/libs/rs/java/tests/src/com/android/rs/test/rstypes.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/rstypes.rs
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs
diff --git a/libs/rs/java/tests/src/com/android/rs/test/shared.rsh b/tests/RenderScriptTests/tests/src/com/android/rs/test/shared.rsh
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/shared.rsh
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/shared.rsh
diff --git a/libs/rs/java/tests/src/com/android/rs/test/test_root.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/test_root.rs
similarity index 100%
rename from libs/rs/java/tests/src/com/android/rs/test/test_root.rs
rename to tests/RenderScriptTests/tests/src/com/android/rs/test/test_root.rs
diff --git a/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml b/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml
index 5211b0a..d3c492e 100644
--- a/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml
+++ b/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml
@@ -9,5 +9,7 @@
 			android:layout_width="wrap_content"/>
 	<ImageView
 			android:layout_height="wrap_content"
-			android:layout_width="wrap_content"/>
+			android:layout_width="wrap_content"
+			android:layout_marginLeft="3dip"
+			android:layout_marginRight="5dip"/>
 </merge>
diff --git a/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java
index e193477..a50a2bd 100644
--- a/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java
@@ -63,7 +63,7 @@
     @LayoutlibDelegate
     /*package*/ static int nativeCreate(int opColor, int tolerance, int nativeMode) {
         AvoidXfermode_Delegate newDelegate = new AvoidXfermode_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
index c6fde7b..9a8cf04 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
@@ -76,7 +76,7 @@
                 bitmap.getImage(),
                 Shader_Delegate.getTileMode(shaderTileModeX),
                 Shader_Delegate.getTileMode(shaderTileModeY));
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 0c87766..66e59d8 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -54,7 +54,7 @@
 
     // ---- delegate manager ----
     private static final DelegateManager<Bitmap_Delegate> sManager =
-            new DelegateManager<Bitmap_Delegate>();
+            new DelegateManager<Bitmap_Delegate>(Bitmap_Delegate.class);
 
     // ---- delegate helper data ----
 
@@ -245,12 +245,12 @@
 
     @LayoutlibDelegate
     /*package*/ static void nativeDestructor(int nativeBitmap) {
-        sManager.removeDelegate(nativeBitmap);
+        sManager.removeJavaReferenceFor(nativeBitmap);
     }
 
     @LayoutlibDelegate
     /*package*/ static void nativeRecycle(int nativeBitmap) {
-        sManager.removeDelegate(nativeBitmap);
+        sManager.removeJavaReferenceFor(nativeBitmap);
     }
 
     @LayoutlibDelegate
@@ -522,7 +522,7 @@
 
     private static Bitmap createBitmap(Bitmap_Delegate delegate, boolean isMutable, int density) {
         // get its native_int
-        int nativeInt = sManager.addDelegate(delegate);
+        int nativeInt = sManager.addNewDelegate(delegate);
 
         // and create/return a new Bitmap with it
         return new Bitmap(nativeInt, null /* buffer */, isMutable, null /*ninePatchChunk*/, density);
diff --git a/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java
index 92d0d0a..4becba1 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java
@@ -57,7 +57,7 @@
     @LayoutlibDelegate
     /*package*/ static int nativeConstructor(float radius, int style) {
         BlurMaskFilter_Delegate newDelegate = new BlurMaskFilter_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index e8a99b5..4decd1a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -54,7 +54,7 @@
 
     // ---- delegate manager ----
     private static final DelegateManager<Canvas_Delegate> sManager =
-            new DelegateManager<Canvas_Delegate>();
+            new DelegateManager<Canvas_Delegate>(Canvas_Delegate.class);
 
     // ---- delegate helper data ----
 
@@ -64,7 +64,7 @@
     private Bitmap_Delegate mBitmap;
     private GcSnapshot mSnapshot;
 
-    private int mDrawFilter = 0;
+    private DrawFilter_Delegate mDrawFilter = null;
 
     // ---- Public Helper methods ----
 
@@ -95,7 +95,7 @@
      * @return the delegate or null.
      */
     public DrawFilter_Delegate getDrawFilter() {
-        return DrawFilter_Delegate.getDelegate(mDrawFilter);
+        return mDrawFilter;
     }
 
     // ---- native methods ----
@@ -313,12 +313,12 @@
             // create a new Canvas_Delegate with the given bitmap and return its new native int.
             Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate);
 
-            return sManager.addDelegate(newDelegate);
+            return sManager.addNewDelegate(newDelegate);
         } else {
             // create a new Canvas_Delegate and return its new native int.
             Canvas_Delegate newDelegate = new Canvas_Delegate();
 
-            return sManager.addDelegate(newDelegate);
+            return sManager.addNewDelegate(newDelegate);
         }
     }
 
@@ -510,26 +510,18 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nativeSetDrawFilter(int nativeCanvas,
-                                                   int nativeFilter) {
+    /*package*/ static void nativeSetDrawFilter(int nativeCanvas, int nativeFilter) {
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
             return;
         }
 
-        canvasDelegate.mDrawFilter = nativeFilter;
+        canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter);
 
-        // get the delegate only because we don't support them at all for the moment, so
-        // we can display the message now.
-
-        DrawFilter_Delegate filterDelegate = DrawFilter_Delegate.getDelegate(nativeFilter);
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        if (filterDelegate.isSupported() == false) {
+        if (canvasDelegate.mDrawFilter != null &&
+                canvasDelegate.mDrawFilter.isSupported() == false) {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER,
-                    filterDelegate.getSupportMessage(), null, null /*data*/);
+                    canvasDelegate.mDrawFilter.getSupportMessage(), null, null /*data*/);
         }
     }
 
@@ -956,7 +948,7 @@
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
             public void draw(Graphics2D graphics, Paint_Delegate paint) {
-                // WARNING: the logic in this method is similar to Paint.measureText.
+                // WARNING: the logic in this method is similar to Paint_Delegate.measureText.
                 // Any change to this method should be reflected in Paint.measureText
                 // Paint.TextAlign indicates how the text is positioned relative to X.
                 // LEFT is the default and there's nothing to do.
@@ -1139,7 +1131,7 @@
         canvasDelegate.dispose();
 
         // remove it from the manager.
-        sManager.removeDelegate(nativeCanvas);
+        sManager.removeJavaReferenceFor(nativeCanvas);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
index 789c6e6..e5a7ab6 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
@@ -38,7 +38,7 @@
 
     // ---- delegate manager ----
     protected static final DelegateManager<ColorFilter_Delegate> sManager =
-            new DelegateManager<ColorFilter_Delegate>();
+            new DelegateManager<ColorFilter_Delegate>(ColorFilter_Delegate.class);
 
     // ---- delegate helper data ----
 
@@ -57,7 +57,7 @@
 
     @LayoutlibDelegate
     /*package*/ static void finalizer(int native_instance, int nativeColorFilter) {
-        sManager.removeDelegate(native_instance);
+        sManager.removeJavaReferenceFor(native_instance);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
index 462b1e6..2de344b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
@@ -57,7 +57,7 @@
     @LayoutlibDelegate
     /*package*/ static int nativeColorMatrixFilter(float[] array) {
         ColorMatrixColorFilter_Delegate newDelegate = new ColorMatrixColorFilter_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java
index 2bdaa5b..7c04a87 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java
@@ -64,7 +64,7 @@
     @LayoutlibDelegate
     /*package*/ static int nativeCreate(int outerpe, int innerpe) {
         ComposePathEffect_Delegate newDelegate = new ComposePathEffect_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
index a2ecb8f..f6e1d00 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
@@ -67,7 +67,7 @@
             int native_mode) {
         // FIXME not supported yet.
         ComposeShader_Delegate newDelegate = new ComposeShader_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
@@ -75,7 +75,7 @@
             int porterDuffMode) {
         // FIXME not supported yet.
         ComposeShader_Delegate newDelegate = new ComposeShader_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java
index c677de8..b0f8168 100644
--- a/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java
@@ -64,7 +64,7 @@
     @LayoutlibDelegate
     /*package*/ static int nativeCreate(float radius) {
         CornerPathEffect_Delegate newDelegate = new CornerPathEffect_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java
index 12a4d4a..d97c2ec 100644
--- a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java
@@ -75,7 +75,7 @@
     @LayoutlibDelegate
     /*package*/ static int nativeCreate(float intervals[], float phase) {
         DashPathEffect_Delegate newDelegate = new DashPathEffect_Delegate(intervals, phase);
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java
index ac69712..ec4a810 100644
--- a/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java
@@ -64,7 +64,7 @@
     @LayoutlibDelegate
     /*package*/ static int nativeCreate(float length, float deviation) {
         DiscretePathEffect_Delegate newDelegate = new DiscretePathEffect_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java
index a98f0a9..870c46b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java
@@ -38,7 +38,7 @@
 
     // ---- delegate manager ----
     protected static final DelegateManager<DrawFilter_Delegate> sManager =
-            new DelegateManager<DrawFilter_Delegate>();
+            new DelegateManager<DrawFilter_Delegate>(DrawFilter_Delegate.class);
 
     // ---- delegate helper data ----
 
@@ -57,7 +57,7 @@
 
     @LayoutlibDelegate
     /*package*/ static void nativeDestructor(int nativeDrawFilter) {
-        sManager.removeDelegate(nativeDrawFilter);
+        sManager.removeJavaReferenceFor(nativeDrawFilter);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java
index 31f8bbf..ebc1c1d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java
@@ -58,7 +58,7 @@
     /*package*/ static int nativeConstructor(float[] direction, float ambient,
             float specular, float blurRadius) {
         EmbossMaskFilter_Delegate newDelegate = new EmbossMaskFilter_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
index fcb62a8..51e0576 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
@@ -57,7 +57,7 @@
     @LayoutlibDelegate
     /*package*/ static int nativeConstructor() {
         LayerRasterizer_Delegate newDelegate = new LayerRasterizer_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
index b272534..0ee883d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
@@ -57,7 +57,7 @@
     @LayoutlibDelegate
     /*package*/ static int native_CreateLightingFilter(int mul, int add) {
         LightingColorFilter_Delegate newDelegate = new LightingColorFilter_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
index 8060577..a2ba758 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
@@ -59,7 +59,7 @@
             int colors[], float positions[], int tileMode) {
         LinearGradient_Delegate newDelegate = new LinearGradient_Delegate(x0, y0, x1, y1,
                 colors, positions, Shader_Delegate.getTileMode(tileMode));
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java
index 4adca27..c2f27e4 100644
--- a/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java
@@ -38,7 +38,7 @@
 
     // ---- delegate manager ----
     protected static final DelegateManager<MaskFilter_Delegate> sManager =
-            new DelegateManager<MaskFilter_Delegate>();
+            new DelegateManager<MaskFilter_Delegate>(MaskFilter_Delegate.class);
 
     // ---- delegate helper data ----
 
@@ -57,7 +57,7 @@
 
     @LayoutlibDelegate
     /*package*/ static void nativeDestructor(int native_filter) {
-        sManager.removeDelegate(native_filter);
+        sManager.removeJavaReferenceFor(native_filter);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index 68a476f..451edd2 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -46,7 +46,7 @@
 
     // ---- delegate manager ----
     private static final DelegateManager<Matrix_Delegate> sManager =
-            new DelegateManager<Matrix_Delegate>();
+            new DelegateManager<Matrix_Delegate>(Matrix_Delegate.class);
 
     // ---- delegate data ----
     private float mValues[] = new float[MATRIX_SIZE];
@@ -189,7 +189,7 @@
             }
         }
 
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
@@ -765,7 +765,7 @@
 
     @LayoutlibDelegate
     /*package*/ static void finalizer(int native_instance) {
-        sManager.removeDelegate(native_instance);
+        sManager.removeJavaReferenceFor(native_instance);
     }
 
     // ---- Private helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java
index dfcb591..71d346a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java
@@ -57,7 +57,7 @@
     @LayoutlibDelegate
     /*package*/ static int nativeConstructor(int clearBits, int setBits) {
         PaintFlagsDrawFilter_Delegate newDelegate = new PaintFlagsDrawFilter_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index f5d2547..373f482 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -32,6 +32,7 @@
 import java.awt.Toolkit;
 import java.awt.font.FontRenderContext;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -61,7 +62,7 @@
 
     // ---- delegate manager ----
     private static final DelegateManager<Paint_Delegate> sManager =
-            new DelegateManager<Paint_Delegate>();
+            new DelegateManager<Paint_Delegate>(Paint_Delegate.class);
 
     // ---- delegate helper data ----
     private List<FontInfo> mFonts;
@@ -75,19 +76,19 @@
     private int mCap;
     private int mJoin;
     private int mTextAlign;
-    private int mTypeface;
+    private Typeface_Delegate mTypeface;
     private float mStrokeWidth;
     private float mStrokeMiter;
     private float mTextSize;
     private float mTextScaleX;
     private float mTextSkewX;
 
-    private int mXfermode;
-    private int mColorFilter;
-    private int mShader;
-    private int mPathEffect;
-    private int mMaskFilter;
-    private int mRasterizer;
+    private Xfermode_Delegate mXfermode;
+    private ColorFilter_Delegate mColorFilter;
+    private Shader_Delegate mShader;
+    private PathEffect_Delegate mPathEffect;
+    private MaskFilter_Delegate mMaskFilter;
+    private Rasterizer_Delegate mRasterizer;
 
 
     // ---- Public Helper methods ----
@@ -172,17 +173,16 @@
     }
 
     public Stroke getJavaStroke() {
-        PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate(mPathEffect);
-        if (effectDelegate != null) {
-            if (effectDelegate.isSupported()) {
-                Stroke stroke = effectDelegate.getStroke(this);
+        if (mPathEffect != null) {
+            if (mPathEffect.isSupported()) {
+                Stroke stroke = mPathEffect.getStroke(this);
                 assert stroke != null;
                 if (stroke != null) {
                     return stroke;
                 }
             } else {
                 Bridge.getLog().fidelityWarning(LayoutLog.TAG_PATHEFFECT,
-                        effectDelegate.getSupportMessage(),
+                        mPathEffect.getSupportMessage(),
                         null, null /*data*/);
             }
         }
@@ -201,7 +201,7 @@
      * @return the delegate or null.
      */
     public Xfermode_Delegate getXfermode() {
-        return  Xfermode_Delegate.getDelegate(mXfermode);
+        return mXfermode;
     }
 
     /**
@@ -210,7 +210,7 @@
      * @return the delegate or null.
      */
     public ColorFilter_Delegate getColorFilter() {
-        return ColorFilter_Delegate.getDelegate(mColorFilter);
+        return mColorFilter;
     }
 
     /**
@@ -219,7 +219,7 @@
      * @return the delegate or null.
      */
     public Shader_Delegate getShader() {
-        return Shader_Delegate.getDelegate(mShader);
+        return mShader;
     }
 
     /**
@@ -228,7 +228,7 @@
      * @return the delegate or null.
      */
     public MaskFilter_Delegate getMaskFilter() {
-        return MaskFilter_Delegate.getDelegate(mMaskFilter);
+        return mMaskFilter;
     }
 
     /**
@@ -237,7 +237,7 @@
      * @return the delegate or null.
      */
     public Rasterizer_Delegate getRasterizer() {
-        return Rasterizer_Delegate.getDelegate(mRasterizer);
+        return mRasterizer;
     }
 
     // ---- native methods ----
@@ -542,9 +542,6 @@
     @LayoutlibDelegate
     /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
             int count) {
-        // WARNING: the logic in this method is similar to Canvas.drawText.
-        // Any change to this method should be reflected in Canvas.drawText
-
         // get the delegate
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
         if (delegate == null) {
@@ -567,25 +564,57 @@
     @LayoutlibDelegate
     /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
             float maxWidth, float[] measuredWidth) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Paint.native_breakText is not supported.", null, null /*data*/);
-        return 0;
+
+        // get the delegate
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            return 0;
+        }
+
+        int inc = count > 0 ? 1 : -1;
+
+        int measureIndex = 0;
+        float measureAcc = 0;
+        for (int i = index; i != index + count; i += inc, measureIndex++) {
+            int start, end;
+            if (i < index) {
+                start = i;
+                end = index;
+            } else {
+                start = index;
+                end = i;
+            }
+
+            // measure from start to end
+            float res = delegate.measureText(text, start, end - start + 1);
+
+            if (measuredWidth != null) {
+                measuredWidth[measureIndex] = res;
+            }
+
+            measureAcc += res;
+            if (res > maxWidth) {
+                // we should not return this char index, but since it's 0-based
+                // and we need to return a count, we simply return measureIndex;
+                return measureIndex;
+            }
+
+        }
+
+        return measureIndex;
     }
 
     @LayoutlibDelegate
     /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
             float maxWidth, float[] measuredWidth) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Paint.native_breakText is not supported.", null, null /*data*/);
-        return 0;
+        return native_breakText(thisPaint, text.toCharArray(), 0, text.length(), maxWidth,
+                measuredWidth);
     }
 
     @LayoutlibDelegate
     /*package*/ static int native_init() {
         Paint_Delegate newDelegate = new Paint_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
@@ -597,7 +626,7 @@
         }
 
         Paint_Delegate newDelegate = new Paint_Delegate(delegate);
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
@@ -728,7 +757,9 @@
             return shader;
         }
 
-        return delegate.mShader = shader;
+        delegate.mShader = Shader_Delegate.getDelegate(shader);
+
+        return shader;
     }
 
     @LayoutlibDelegate
@@ -739,13 +770,12 @@
             return filter;
         }
 
-        delegate.mColorFilter = filter;
+        delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter);;
 
         // since none of those are supported, display a fidelity warning right away
-        ColorFilter_Delegate filterDelegate = delegate.getColorFilter();
-        if (filterDelegate != null && filterDelegate.isSupported() == false) {
+        if (delegate.mColorFilter != null && delegate.mColorFilter.isSupported() == false) {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_COLORFILTER,
-                    filterDelegate.getSupportMessage(), null, null /*data*/);
+                    delegate.mColorFilter.getSupportMessage(), null, null /*data*/);
         }
 
         return filter;
@@ -759,7 +789,9 @@
             return xfermode;
         }
 
-        return delegate.mXfermode = xfermode;
+        delegate.mXfermode = Xfermode_Delegate.getDelegate(xfermode);
+
+        return xfermode;
     }
 
     @LayoutlibDelegate
@@ -770,7 +802,9 @@
             return effect;
         }
 
-        return delegate.mPathEffect = effect;
+        delegate.mPathEffect = PathEffect_Delegate.getDelegate(effect);
+
+        return effect;
     }
 
     @LayoutlibDelegate
@@ -781,13 +815,12 @@
             return maskfilter;
         }
 
-        delegate.mMaskFilter = maskfilter;
+        delegate.mMaskFilter = MaskFilter_Delegate.getDelegate(maskfilter);
 
         // since none of those are supported, display a fidelity warning right away
-        MaskFilter_Delegate filterDelegate = delegate.getMaskFilter();
-        if (filterDelegate != null && filterDelegate.isSupported() == false) {
+        if (delegate.mMaskFilter != null && delegate.mMaskFilter.isSupported() == false) {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER,
-                    filterDelegate.getSupportMessage(), null, null /*data*/);
+                    delegate.mMaskFilter.getSupportMessage(), null, null /*data*/);
         }
 
         return maskfilter;
@@ -801,9 +834,9 @@
             return 0;
         }
 
-        delegate.mTypeface = typeface;
+        delegate.mTypeface = Typeface_Delegate.getDelegate(typeface);
         delegate.updateFontObject();
-        return delegate.mTypeface;
+        return typeface;
     }
 
     @LayoutlibDelegate
@@ -814,13 +847,12 @@
             return rasterizer;
         }
 
-        delegate.mRasterizer = rasterizer;
+        delegate.mRasterizer = Rasterizer_Delegate.getDelegate(rasterizer);
 
         // since none of those are supported, display a fidelity warning right away
-        Rasterizer_Delegate rasterizerDelegate = delegate.getRasterizer();
-        if (rasterizerDelegate != null && rasterizerDelegate.isSupported() == false) {
+        if (delegate.mRasterizer != null && delegate.mRasterizer.isSupported() == false) {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_RASTERIZER,
-                    rasterizerDelegate.getSupportMessage(), null, null /*data*/);
+                    delegate.mRasterizer.getSupportMessage(), null, null /*data*/);
         }
 
         return rasterizer;
@@ -862,19 +894,49 @@
     @LayoutlibDelegate
     /*package*/ static int native_getTextWidths(int native_object, char[] text, int index,
             int count, float[] widths) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Paint.getTextWidths is not supported.", null, null /*data*/);
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(native_object);
+        if (delegate == null) {
+            return 0;
+        }
+
+        if (delegate.mFonts.size() > 0) {
+            // FIXME: handle multi-char characters (see measureText)
+            float totalAdvance = 0;
+            for (int i = 0; i < count; i++) {
+                char c = text[i + index];
+                boolean found = false;
+                for (FontInfo info : delegate.mFonts) {
+                    if (info.mFont.canDisplay(c)) {
+                        float adv = info.mMetrics.charWidth(c);
+                        totalAdvance += adv;
+                        if (widths != null) {
+                            widths[i] = adv;
+                        }
+
+                        found = true;
+                        break;
+                    }
+                }
+
+                if (found == false) {
+                    // no advance for this char.
+                    if (widths != null) {
+                        widths[i] = 0.f;
+                    }
+                }
+            }
+
+            return (int) totalAdvance;
+        }
+
         return 0;
     }
 
     @LayoutlibDelegate
     /*package*/ static int native_getTextWidths(int native_object, String text, int start,
             int end, float[] widths) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Paint.getTextWidths is not supported.", null, null /*data*/);
-        return 0;
+        return native_getTextWidths(native_object, text.toCharArray(), start, end - start, widths);
     }
 
     @LayoutlibDelegate
@@ -971,22 +1033,33 @@
     @LayoutlibDelegate
     /*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start,
             int end, Rect bounds) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Paint.getStringBounds is not supported.", null, null /*data*/);
+        nativeGetCharArrayBounds(nativePaint, text.toCharArray(), start, end - start, bounds);
     }
 
     @LayoutlibDelegate
     /*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index,
             int count, Rect bounds) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Paint.getCharArrayBounds is not supported.", null, null /*data*/);
+
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
+        if (delegate == null) {
+            return;
+        }
+
+        // FIXME should test if the main font can display all those characters.
+        // See MeasureText
+        if (delegate.mFonts.size() > 0) {
+            FontInfo mainInfo = delegate.mFonts.get(0);
+
+            Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count,
+                    delegate.mFontContext);
+            bounds.set(0, 0, (int) rect.getWidth(), (int) rect.getHeight());
+        }
     }
 
     @LayoutlibDelegate
     /*package*/ static void finalizer(int nativePaint) {
-        sManager.removeDelegate(nativePaint);
+        sManager.removeJavaReferenceFor(nativePaint);
     }
 
     // ---- Private delegate/helper methods ----
@@ -1028,18 +1101,18 @@
         mCap = Paint.Cap.BUTT.nativeInt;
         mJoin = Paint.Join.MITER.nativeInt;
         mTextAlign = 0;
-        mTypeface = Typeface.sDefaults[0].native_instance;
+        mTypeface = Typeface_Delegate.getDelegate(Typeface.sDefaults[0].native_instance);
         mStrokeWidth = 1.f;
         mStrokeMiter = 4.f;
         mTextSize = 20.f;
         mTextScaleX = 1.f;
         mTextSkewX = 0.f;
-        mXfermode = 0;
-        mColorFilter = 0;
-        mShader = 0;
-        mPathEffect = 0;
-        mMaskFilter = 0;
-        mRasterizer = 0;
+        mXfermode = null;
+        mColorFilter = null;
+        mShader = null;
+        mPathEffect = null;
+        mMaskFilter = null;
+        mRasterizer = null;
         updateFontObject();
     }
 
@@ -1048,9 +1121,9 @@
      */
     @SuppressWarnings("deprecation")
     private void updateFontObject() {
-        if (mTypeface != 0) {
+        if (mTypeface != null) {
             // Get the fonts from the TypeFace object.
-            List<Font> fonts = Typeface_Delegate.getFonts(mTypeface);
+            List<Font> fonts = mTypeface.getFonts();
 
             // create new font objects as well as FontMetrics, based on the current text size
             // and skew info.
@@ -1073,6 +1146,10 @@
     }
 
     /*package*/ float measureText(char[] text, int index, int count) {
+
+        // WARNING: the logic in this method is similar to Canvas_Delegate.native_drawText
+        // Any change to this method should be reflected there as well
+
         if (mFonts.size() > 0) {
             FontInfo mainFont = mFonts.get(0);
             int i = index;
@@ -1120,6 +1197,8 @@
                     i += size;
                 }
             }
+
+            return total;
         }
 
         return 0;
diff --git a/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java
index 98a5386..c448f0e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java
@@ -65,7 +65,7 @@
     /*package*/ static int nativeCreate(int native_path, float advance, float phase,
             int native_style) {
         PathDashPathEffect_Delegate newDelegate = new PathDashPathEffect_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java
index bbbebdd..bd2b6de 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java
@@ -40,7 +40,7 @@
 
     // ---- delegate manager ----
     protected static final DelegateManager<PathEffect_Delegate> sManager =
-            new DelegateManager<PathEffect_Delegate>();
+            new DelegateManager<PathEffect_Delegate>(PathEffect_Delegate.class);
 
     // ---- delegate helper data ----
 
@@ -61,7 +61,7 @@
 
     @LayoutlibDelegate
     /*package*/ static void nativeDestructor(int native_patheffect) {
-        sManager.removeDelegate(native_patheffect);
+        sManager.removeJavaReferenceFor(native_patheffect);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 9510ce0..6c9f48f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -50,7 +50,7 @@
 
     // ---- delegate manager ----
     private static final DelegateManager<Path_Delegate> sManager =
-            new DelegateManager<Path_Delegate>();
+            new DelegateManager<Path_Delegate>(Path_Delegate.class);
 
     // ---- delegate data ----
     private FillType mFillType = FillType.WINDING;
@@ -90,7 +90,7 @@
         // create the delegate
         Path_Delegate newDelegate = new Path_Delegate();
 
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
@@ -104,7 +104,7 @@
             newDelegate.set(pathDelegate);
         }
 
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
@@ -440,7 +440,7 @@
 
     @LayoutlibDelegate
     /*package*/ static void finalizer(int nPath) {
-        sManager.removeDelegate(nPath);
+        sManager.removeJavaReferenceFor(nPath);
     }
 
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java
index bbb20e9..4ab044b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java
@@ -63,7 +63,7 @@
     @LayoutlibDelegate
     /*package*/ static int nativeCreate(int opColor) {
         PixelXorXfermode_Delegate newDelegate = new PixelXorXfermode_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
index 33f6c44..c45dbaa 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
@@ -57,7 +57,7 @@
     @LayoutlibDelegate
     /*package*/ static int native_CreatePorterDuffFilter(int srcColor, int porterDuffMode) {
         PorterDuffColorFilter_Delegate newDelegate = new PorterDuffColorFilter_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
index 116a773..4301c1a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
@@ -129,7 +129,7 @@
     @LayoutlibDelegate
     /*package*/ static int nativeCreateXfermode(int mode) {
         PorterDuffXfermode_Delegate newDelegate = new PorterDuffXfermode_Delegate(mode);
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
index 8723ed1..9bf78b4 100644
--- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -58,7 +58,7 @@
             int colors[], float positions[], int tileMode) {
         RadialGradient_Delegate newDelegate = new RadialGradient_Delegate(x, y, radius,
                 colors, positions, Shader_Delegate.getTileMode(tileMode));
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
index 2826278..2812b6b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
@@ -38,7 +38,7 @@
 
     // ---- delegate manager ----
     protected static final DelegateManager<Rasterizer_Delegate> sManager =
-            new DelegateManager<Rasterizer_Delegate>();
+            new DelegateManager<Rasterizer_Delegate>(Rasterizer_Delegate.class);
 
     // ---- delegate helper data ----
 
@@ -57,7 +57,7 @@
 
     @LayoutlibDelegate
     /*package*/ static void finalizer(int native_instance) {
-        sManager.removeDelegate(native_instance);
+        sManager.removeJavaReferenceFor(native_instance);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
index 7b91215..cb31b8f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
@@ -48,7 +48,7 @@
 
     // ---- delegate manager ----
     protected static final DelegateManager<Region_Delegate> sManager =
-            new DelegateManager<Region_Delegate>();
+            new DelegateManager<Region_Delegate>(Region_Delegate.class);
 
     // ---- delegate helper data ----
 
@@ -266,12 +266,12 @@
     @LayoutlibDelegate
     /*package*/ static int nativeConstructor() {
         Region_Delegate newDelegate = new Region_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
     /*package*/ static void nativeDestructor(int native_region) {
-        sManager.removeDelegate(native_region);
+        sManager.removeJavaReferenceFor(native_region);
     }
 
     @LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
index a1b8bdd..368c0384 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
@@ -40,12 +40,12 @@
 
     // ---- delegate manager ----
     protected static final DelegateManager<Shader_Delegate> sManager =
-            new DelegateManager<Shader_Delegate>();
+            new DelegateManager<Shader_Delegate>(Shader_Delegate.class);
 
     // ---- delegate helper data ----
 
     // ---- delegate data ----
-    private int mLocalMatrix = 0;
+    private Matrix_Delegate mLocalMatrix = null;
 
     // ---- Public Helper methods ----
 
@@ -77,7 +77,7 @@
 
     @LayoutlibDelegate
     /*package*/ static void nativeDestructor(int native_shader, int native_skiaShader) {
-        sManager.removeDelegate(native_shader);
+        sManager.removeJavaReferenceFor(native_shader);
     }
 
     @LayoutlibDelegate
@@ -89,15 +89,14 @@
             return;
         }
 
-        shaderDelegate.mLocalMatrix = matrix_instance;
+        shaderDelegate.mLocalMatrix = Matrix_Delegate.getDelegate(matrix_instance);
     }
 
     // ---- Private delegate/helper methods ----
 
     protected java.awt.geom.AffineTransform getLocalMatrix() {
-        Matrix_Delegate localMatrixDelegate = Matrix_Delegate.getDelegate(mLocalMatrix);
-        if (localMatrixDelegate != null) {
-            return localMatrixDelegate.getAffineTransform();
+        if (mLocalMatrix != null) {
+            return mLocalMatrix.getAffineTransform();
         }
 
         return new java.awt.geom.AffineTransform();
diff --git a/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java
index 0c9ee48..410df0c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java
@@ -64,7 +64,7 @@
     @LayoutlibDelegate
     /*package*/ static int nativeCreate(int first, int second) {
         SumPathEffect_Delegate newDelegate = new SumPathEffect_Delegate();
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
index 382e34c..966e06e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
@@ -54,7 +54,7 @@
     @LayoutlibDelegate
     /*package*/ static int nativeCreate1(float x, float y, int colors[], float positions[]) {
         SweepGradient_Delegate newDelegate = new SweepGradient_Delegate(x, y, colors, positions);
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 1992341..0f084f7 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -46,7 +46,7 @@
 
     // ---- delegate manager ----
     private static final DelegateManager<Typeface_Delegate> sManager =
-            new DelegateManager<Typeface_Delegate>();
+            new DelegateManager<Typeface_Delegate>(Typeface_Delegate.class);
 
     // ---- delegate helper data ----
     private static final String DEFAULT_FAMILY = "sans-serif";
@@ -74,6 +74,10 @@
         sPostInitDelegate.clear();
     }
 
+    public static Typeface_Delegate getDelegate(int nativeTypeface) {
+        return sManager.getDelegate(nativeTypeface);
+    }
+
     public static List<Font> getFonts(Typeface typeface) {
         return getFonts(typeface.native_instance);
     }
@@ -84,7 +88,11 @@
             return null;
         }
 
-        return delegate.mFonts;
+        return delegate.getFonts();
+    }
+
+    public List<Font> getFonts() {
+        return mFonts;
     }
 
     // ---- native methods ----
@@ -105,7 +113,7 @@
             sPostInitDelegate.add(newDelegate);
         }
 
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
@@ -125,7 +133,7 @@
             sPostInitDelegate.add(newDelegate);
         }
 
-        return sManager.addDelegate(newDelegate);
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
@@ -144,7 +152,7 @@
 
     @LayoutlibDelegate
     /*package*/ static void nativeUnref(int native_instance) {
-        sManager.removeDelegate(native_instance);
+        sManager.removeJavaReferenceFor(native_instance);
     }
 
     @LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java
index 88df027..962d69c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java
@@ -40,7 +40,7 @@
 
     // ---- delegate manager ----
     protected static final DelegateManager<Xfermode_Delegate> sManager =
-            new DelegateManager<Xfermode_Delegate>();
+            new DelegateManager<Xfermode_Delegate>(Xfermode_Delegate.class);
 
     // ---- delegate helper data ----
 
@@ -61,7 +61,7 @@
 
     @LayoutlibDelegate
     /*package*/ static void finalizer(int native_instance) {
-        sManager.removeDelegate(native_instance);
+        sManager.removeJavaReferenceFor(native_instance);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
index 04d06e4..9fab51a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
@@ -30,7 +30,7 @@
 public class PhoneSystemBar extends CustomBar {
 
     public PhoneSystemBar(Context context, Density density) throws XmlPullParserException {
-        super(context, density, "/bars/tablet_system_bar.xml");
+        super(context, density, "/bars/phone_system_bar.xml");
 
         setGravity(mGravity | Gravity.RIGHT);
         setBackgroundColor(0xFF000000);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
index 05a258d..ae1217d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
@@ -16,8 +16,15 @@
 
 package com.android.layoutlib.bridge.impl;
 
+import com.android.layoutlib.bridge.util.Debug;
+import com.android.layoutlib.bridge.util.SparseWeakArray;
+
 import android.util.SparseArray;
 
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Manages native delegates.
  *
@@ -44,15 +51,39 @@
  * will do is call {@link #getDelegate(int)} to get the Java object matching the int.
  *
  * Typical native init methods are returning a new int back to the Java class, so
- * {@link #addDelegate(Object)} does the same.
+ * {@link #addNewDelegate(Object)} does the same.
+ *
+ * The JNI references are counted, so we do the same through a {@link WeakReference}. Because
+ * the Java object needs to count as a reference (even though it only holds an int), we use the
+ * following mechanism:
+ *
+ * - {@link #addNewDelegate(Object)} and {@link #removeJavaReferenceFor(int)} adds and removes
+ *   the delegate to/from a list. This list hold the reference and prevents the GC from reclaiming
+ *   the delegate.
+ *
+ * - {@link #addNewDelegate(Object)} also adds the delegate to a {@link SparseArray} that holds a
+ *   {@link WeakReference} to the delegate. This allows the delegate to be deleted automatically
+ *   when nothing references it. This means that any class that holds a delegate (except for the
+ *   Java main class) must not use the int but the Delegate class instead. The integers must
+ *   only be used in the API between the main Java class and the Delegate.
  *
  * @param <T> the delegate class to manage
  */
 public final class DelegateManager<T> {
-
-    private final SparseArray<T> mDelegates = new SparseArray<T>();
+    private final Class<T> mClass;
+    private final SparseWeakArray<T> mDelegates = new SparseWeakArray<T>();
+    /** list used to store delegates when their main object holds a reference to them.
+     * This is to ensure that the WeakReference in the SparseWeakArray doesn't get GC'ed
+     * @see #addNewDelegate(Object)
+     * @see #removeJavaReferenceFor(int)
+     */
+    private final List<T> mJavaReferences = new ArrayList<T>();
     private int mDelegateCounter = 0;
 
+    public DelegateManager(Class<T> theClass) {
+        mClass = theClass;
+    }
+
     /**
      * Returns the delegate from the given native int.
      * <p>
@@ -66,6 +97,14 @@
     public T getDelegate(int native_object) {
         if (native_object > 0) {
             T delegate =  mDelegates.get(native_object);
+
+            if (Debug.DEBUG) {
+                if (delegate == null) {
+                    System.out.println("Unknown " + mClass.getSimpleName() + " with int " +
+                            native_object);
+                }
+            }
+
             assert delegate != null;
             return delegate;
         }
@@ -77,17 +116,31 @@
      * @param newDelegate the delegate to add
      * @return a unique native int to identify the delegate
      */
-    public int addDelegate(T newDelegate) {
+    public int addNewDelegate(T newDelegate) {
         int native_object = ++mDelegateCounter;
         mDelegates.put(native_object, newDelegate);
+        assert !mJavaReferences.contains(newDelegate);
+        mJavaReferences.add(newDelegate);
+
+        if (Debug.DEBUG) {
+            System.out.println("New " + mClass.getSimpleName() + " with int " + native_object);
+        }
+
         return native_object;
     }
 
     /**
-     * Removes the delegate matching the given native int.
-     * @param native_object the native int.
+     * Removes the main reference on the given delegate.
+     * @param native_object the native integer representing the delegate.
      */
-    public void removeDelegate(int native_object) {
-        mDelegates.remove(native_object);
+    public void removeJavaReferenceFor(int native_object) {
+        T delegate = getDelegate(native_object);
+
+        if (Debug.DEBUG) {
+            System.out.println("Removing main Java ref on " + mClass.getSimpleName() +
+                    " with int " + native_object);
+        }
+
+        mJavaReferences.remove(delegate);
     }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/Debug.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/Debug.java
new file mode 100644
index 0000000..82eab85
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/Debug.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.util;
+
+public class Debug {
+
+    public final static boolean DEBUG = false;
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java
new file mode 100644
index 0000000..4d0c9ce
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.util;
+
+
+import com.android.internal.util.ArrayUtils;
+
+import android.util.SparseArray;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * This is a custom {@link SparseArray} that uses {@link WeakReference} around the objects added
+ * to it. When the array is compacted, not only deleted indices but also empty references
+ * are removed, making the array efficient at removing references that were reclaimed.
+ *
+ * The code is taken from {@link SparseArray} directly and adapted to use weak references.
+ *
+ * Because our usage means that we never actually call {@link #remove(int)} or {@link #delete(int)},
+ * we must manually check if there are reclaimed references to trigger an internal compact step
+ * (which is normally only triggered when an item is manually removed).
+ *
+ * SparseArrays map integers to Objects.  Unlike a normal array of Objects,
+ * there can be gaps in the indices.  It is intended to be more efficient
+ * than using a HashMap to map Integers to Objects.
+ */
+@SuppressWarnings("unchecked")
+public class SparseWeakArray<E> {
+
+    private static final Object DELETED_REF = new Object();
+    private static final WeakReference<?> DELETED = new WeakReference(DELETED_REF);
+    private boolean mGarbage = false;
+
+    /**
+     * Creates a new SparseArray containing no mappings.
+     */
+    public SparseWeakArray() {
+        this(10);
+    }
+
+    /**
+     * Creates a new SparseArray containing no mappings that will not
+     * require any additional memory allocation to store the specified
+     * number of mappings.
+     */
+    public SparseWeakArray(int initialCapacity) {
+        initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
+
+        mKeys = new int[initialCapacity];
+        mValues = new WeakReference[initialCapacity];
+        mSize = 0;
+    }
+
+    /**
+     * Gets the Object mapped from the specified key, or <code>null</code>
+     * if no such mapping has been made.
+     */
+    public E get(int key) {
+        return get(key, null);
+    }
+
+    /**
+     * Gets the Object mapped from the specified key, or the specified Object
+     * if no such mapping has been made.
+     */
+    public E get(int key, E valueIfKeyNotFound) {
+        int i = binarySearch(mKeys, 0, mSize, key);
+
+        if (i < 0 || mValues[i] == DELETED || mValues[i].get() == null) {
+            return valueIfKeyNotFound;
+        } else {
+            return (E) mValues[i].get();
+        }
+    }
+
+    /**
+     * Removes the mapping from the specified key, if there was any.
+     */
+    public void delete(int key) {
+        int i = binarySearch(mKeys, 0, mSize, key);
+
+        if (i >= 0) {
+            if (mValues[i] != DELETED) {
+                mValues[i] = DELETED;
+                mGarbage = true;
+            }
+        }
+    }
+
+    /**
+     * Alias for {@link #delete(int)}.
+     */
+    public void remove(int key) {
+        delete(key);
+    }
+
+    /**
+     * Removes the mapping at the specified index.
+     */
+    public void removeAt(int index) {
+        if (mValues[index] != DELETED) {
+            mValues[index] = DELETED;
+            mGarbage = true;
+        }
+    }
+
+    private void gc() {
+        int n = mSize;
+        int o = 0;
+        int[] keys = mKeys;
+        WeakReference<?>[] values = mValues;
+
+        for (int i = 0; i < n; i++) {
+            WeakReference<?> val = values[i];
+
+            // Don't keep any non DELETED values, but only the one that still have a valid
+            // reference.
+            if (val != DELETED && val.get() != null) {
+                if (i != o) {
+                    keys[o] = keys[i];
+                    values[o] = val;
+                }
+
+                o++;
+            }
+        }
+
+        mGarbage = false;
+        mSize = o;
+
+        int newSize = ArrayUtils.idealIntArraySize(mSize);
+        if (newSize < mKeys.length) {
+            int[] nkeys = new int[newSize];
+            WeakReference<?>[] nvalues = new WeakReference[newSize];
+
+            System.arraycopy(mKeys, 0, nkeys, 0, newSize);
+            System.arraycopy(mValues, 0, nvalues, 0, newSize);
+
+            mKeys = nkeys;
+            mValues = nvalues;
+        }
+    }
+
+    /**
+     * Adds a mapping from the specified key to the specified value,
+     * replacing the previous mapping from the specified key if there
+     * was one.
+     */
+    public void put(int key, E value) {
+        int i = binarySearch(mKeys, 0, mSize, key);
+
+        if (i >= 0) {
+            mValues[i] = new WeakReference(value);
+        } else {
+            i = ~i;
+
+            if (i < mSize && (mValues[i] == DELETED || mValues[i].get() == null)) {
+                mKeys[i] = key;
+                mValues[i] = new WeakReference(value);
+                return;
+            }
+
+            if (mSize >= mKeys.length && (mGarbage || hasReclaimedRefs())) {
+                gc();
+
+                // Search again because indices may have changed.
+                i = ~binarySearch(mKeys, 0, mSize, key);
+            }
+
+            if (mSize >= mKeys.length) {
+                int n = ArrayUtils.idealIntArraySize(mSize + 1);
+
+                int[] nkeys = new int[n];
+                WeakReference<?>[] nvalues = new WeakReference[n];
+
+                // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+                mKeys = nkeys;
+                mValues = nvalues;
+            }
+
+            if (mSize - i != 0) {
+                // Log.e("SparseArray", "move " + (mSize - i));
+                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+            }
+
+            mKeys[i] = key;
+            mValues[i] = new WeakReference(value);
+            mSize++;
+        }
+    }
+
+    /**
+     * Returns the number of key-value mappings that this SparseArray
+     * currently stores.
+     */
+    public int size() {
+        if (mGarbage) {
+            gc();
+        }
+
+        return mSize;
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, returns
+     * the key from the <code>index</code>th key-value mapping that this
+     * SparseArray stores.
+     */
+    public int keyAt(int index) {
+        if (mGarbage) {
+            gc();
+        }
+
+        return mKeys[index];
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, returns
+     * the value from the <code>index</code>th key-value mapping that this
+     * SparseArray stores.
+     */
+    public E valueAt(int index) {
+        if (mGarbage) {
+            gc();
+        }
+
+        return (E) mValues[index].get();
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, sets a new
+     * value for the <code>index</code>th key-value mapping that this
+     * SparseArray stores.
+     */
+    public void setValueAt(int index, E value) {
+        if (mGarbage) {
+            gc();
+        }
+
+        mValues[index] = new WeakReference(value);
+    }
+
+    /**
+     * Returns the index for which {@link #keyAt} would return the
+     * specified key, or a negative number if the specified
+     * key is not mapped.
+     */
+    public int indexOfKey(int key) {
+        if (mGarbage) {
+            gc();
+        }
+
+        return binarySearch(mKeys, 0, mSize, key);
+    }
+
+    /**
+     * Returns an index for which {@link #valueAt} would return the
+     * specified key, or a negative number if no keys map to the
+     * specified value.
+     * Beware that this is a linear search, unlike lookups by key,
+     * and that multiple keys can map to the same value and this will
+     * find only one of them.
+     */
+    public int indexOfValue(E value) {
+        if (mGarbage) {
+            gc();
+        }
+
+        for (int i = 0; i < mSize; i++)
+            if (mValues[i].get() == value)
+                return i;
+
+        return -1;
+    }
+
+    /**
+     * Removes all key-value mappings from this SparseArray.
+     */
+    public void clear() {
+        int n = mSize;
+        WeakReference<?>[] values = mValues;
+
+        for (int i = 0; i < n; i++) {
+            values[i] = null;
+        }
+
+        mSize = 0;
+        mGarbage = false;
+    }
+
+    /**
+     * Puts a key/value pair into the array, optimizing for the case where
+     * the key is greater than all existing keys in the array.
+     */
+    public void append(int key, E value) {
+        if (mSize != 0 && key <= mKeys[mSize - 1]) {
+            put(key, value);
+            return;
+        }
+
+        if (mSize >= mKeys.length && (mGarbage || hasReclaimedRefs())) {
+            gc();
+        }
+
+        int pos = mSize;
+        if (pos >= mKeys.length) {
+            int n = ArrayUtils.idealIntArraySize(pos + 1);
+
+            int[] nkeys = new int[n];
+            WeakReference<?>[] nvalues = new WeakReference[n];
+
+            // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+            System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+            System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+            mKeys = nkeys;
+            mValues = nvalues;
+        }
+
+        mKeys[pos] = key;
+        mValues[pos] = new WeakReference(value);
+        mSize = pos + 1;
+    }
+
+    private boolean hasReclaimedRefs() {
+        for (int i = 0 ; i < mSize ; i++) {
+            if (mValues[i].get() == null) { // DELETED.get() never returns null.
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private static int binarySearch(int[] a, int start, int len, int key) {
+        int high = start + len, low = start - 1, guess;
+
+        while (high - low > 1) {
+            guess = (high + low) / 2;
+
+            if (a[guess] < key)
+                low = guess;
+            else
+                high = guess;
+        }
+
+        if (high == start + len)
+            return ~(start + len);
+        else if (a[high] == key)
+            return high;
+        else
+            return ~high;
+    }
+
+    private int[] mKeys;
+    private WeakReference<?>[] mValues;
+    private int mSize;
+}
diff --git a/voip/java/com/android/server/sip/SipHelper.java b/voip/java/com/android/server/sip/SipHelper.java
index 518543a..ac580e7 100644
--- a/voip/java/com/android/server/sip/SipHelper.java
+++ b/voip/java/com/android/server/sip/SipHelper.java
@@ -284,6 +284,13 @@
                     mHeaderFactory.createContentTypeHeader(
                             "application", "sdp"));
 
+            // Adding rport argument in the request could fix some SIP servers
+            // in resolving the initiator's NAT port mapping for relaying the
+            // response message from the other end.
+
+            ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
+            if (viaHeader != null) viaHeader.setRPort();
+
             ClientTransaction clientTransaction =
                     mSipProvider.getNewClientTransaction(request);
             if (DEBUG) Log.d(TAG, "send RE-INVITE: " + request);
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 39676b0..909605d 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -170,4 +170,6 @@
      * @return the event string sent by the supplicant.
      */
     public native static String waitForEvent();
+
+    public native static void enableBackgroundScan(boolean enable);
 }
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index fc42ab8..676218e 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -112,9 +112,11 @@
     private String mLastBssid;
     private int mLastNetworkId;
     private boolean mEnableRssiPolling = false;
+    private boolean mEnableBackgroundScan = false;
     private int mRssiPollToken = 0;
     private int mReconnectCount = 0;
     private boolean mIsScanMode = false;
+    private boolean mScanResultIsPending = false;
 
     private boolean mBluetoothConnectionActive = false;
 
@@ -300,6 +302,8 @@
     static final int CMD_START_WPS                        = 89;
     /* Set the frequency band */
     static final int CMD_SET_FREQUENCY_BAND               = 90;
+    /* Enable background scan for configured networks */
+    static final int CMD_ENABLE_BACKGROUND_SCAN           = 91;
 
     /* Commands from/to the SupplicantStateTracker */
     /* Reset the supplicant state tracker */
@@ -823,6 +827,10 @@
        sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0));
     }
 
+    public void enableBackgroundScan(boolean enabled) {
+       sendMessage(obtainMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0));
+    }
+
     public void enableAllNetworks() {
         sendMessage(CMD_ENABLE_ALL_NETWORKS);
     }
@@ -1538,6 +1546,9 @@
                 case CMD_ENABLE_RSSI_POLL:
                     mEnableRssiPolling = (message.arg1 == 1);
                     break;
+                case CMD_ENABLE_BACKGROUND_SCAN:
+                    mEnableBackgroundScan = (message.arg1 == 1);
+                    break;
                     /* Discard */
                 case CMD_LOAD_DRIVER:
                 case CMD_UNLOAD_DRIVER:
@@ -1973,6 +1984,7 @@
                     eventLoggingEnabled = false;
                     setScanResults(WifiNative.scanResultsCommand());
                     sendScanResultsAvailableBroadcast();
+                    mScanResultIsPending = false;
                     break;
                 case CMD_PING_SUPPLICANT:
                     boolean ok = WifiNative.pingCommand();
@@ -2180,6 +2192,7 @@
                 case CMD_START_SCAN:
                     eventLoggingEnabled = false;
                     WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
+                    mScanResultIsPending = true;
                     break;
                 case CMD_SET_HIGH_PERF_MODE:
                     setHighPerfModeEnabledNative(message.arg1 == 1);
@@ -2681,8 +2694,8 @@
                      * back to CONNECT_MODE.
                      */
                     WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
-                    WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
-                    break;
+                    /* Have the parent state handle the rest */
+                    return NOT_HANDLED;
                     /* Ignore connection to same network */
                 case CMD_CONNECT_NETWORK:
                     int netId = message.arg1;
@@ -2771,21 +2784,35 @@
     }
 
     class DisconnectedState extends HierarchicalState {
+        private boolean mAlarmEnabled = false;
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
 
-            /**
-             * In a disconnected state, an infrequent scan that wakes
-             * up the device is needed to ensure a user connects to
-             * an access point on the move
+            /*
+             * We initiate background scanning if it is enabled, otherwise we
+             * initiate an infrequent scan that wakes up the device to ensure
+             * a user connects to an access point on the move
              */
-            long scanMs = Settings.Secure.getLong(mContext.getContentResolver(),
+            if (mEnableBackgroundScan) {
+                /* If a regular scan result is pending, do not initiate background
+                 * scan until the scan results are returned. This is needed because
+                 * initiating a background scan will cancel the regular scan and
+                 * scan results will not be returned until background scanning is
+                 * cleared
+                 */
+                if (!mScanResultIsPending) {
+                    WifiNative.enableBackgroundScan(true);
+                }
+            } else {
+                long scanMs = Settings.Secure.getLong(mContext.getContentResolver(),
                     Settings.Secure.WIFI_SCAN_INTERVAL_MS, DEFAULT_SCAN_INTERVAL_MS);
 
-            mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
+                mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                     System.currentTimeMillis() + scanMs, scanMs, mScanIntent);
+                mAlarmEnabled = true;
+            }
         }
         @Override
         public boolean processMessage(Message message) {
@@ -2800,6 +2827,10 @@
                         transitionTo(mScanModeState);
                     }
                     break;
+                case CMD_ENABLE_BACKGROUND_SCAN:
+                    mEnableBackgroundScan = (message.arg1 == 1);
+                    WifiNative.enableBackgroundScan(mEnableBackgroundScan);
+                    break;
                     /* Ignore network disconnect */
                 case NETWORK_DISCONNECTION_EVENT:
                     break;
@@ -2808,6 +2839,20 @@
                     setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
                     /* DriverStartedState does the rest of the handling */
                     return NOT_HANDLED;
+                case CMD_START_SCAN:
+                    /* Disable background scan temporarily during a regular scan */
+                    if (mEnableBackgroundScan) {
+                        WifiNative.enableBackgroundScan(false);
+                    }
+                    /* Handled in parent state */
+                    return NOT_HANDLED;
+                case SCAN_RESULTS_EVENT:
+                    /* Re-enable background scan when a pending scan result is received */
+                    if (mEnableBackgroundScan && mScanResultIsPending) {
+                        WifiNative.enableBackgroundScan(true);
+                    }
+                    /* Handled in parent state */
+                    return NOT_HANDLED;
                 default:
                     return NOT_HANDLED;
             }
@@ -2817,7 +2862,14 @@
 
         @Override
         public void exit() {
-            mAlarmManager.cancel(mScanIntent);
+            /* No need for a background scan upon exit from a disconnected state */
+            if (mEnableBackgroundScan) {
+                WifiNative.enableBackgroundScan(false);
+            }
+            if (mAlarmEnabled) {
+                mAlarmManager.cancel(mScanIntent);
+                mAlarmEnabled = false;
+            }
         }
     }