Merge "API support for reporting of changes to call features. (eg VoLTE, VoWIFI, etc)"
diff --git a/api/current.txt b/api/current.txt
index 39f67f7..a39bc79 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23223,6 +23223,7 @@
     field public static final android.net.Uri AUTHORITY_URI;
     field public static final java.lang.String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
     field public static final java.lang.String DEFERRED_SNIPPETING = "deferred_snippeting";
+    field public static final java.lang.String DEFERRED_SNIPPETING_QUERY = "deferred_snippeting_query";
     field public static final java.lang.String DIRECTORY_PARAM_KEY = "directory";
     field public static final java.lang.String LIMIT_PARAM_KEY = "limit";
     field public static final java.lang.String PRIMARY_ACCOUNT_NAME = "name_for_primary_account";
@@ -23888,11 +23889,10 @@
     field public static final android.net.Uri PROFILE_CONTENT_URI;
   }
 
-  public static class ContactsContract.SearchSnippetColumns {
-    ctor public ContactsContract.SearchSnippetColumns();
+  public static class ContactsContract.SearchSnippets {
+    ctor public ContactsContract.SearchSnippets();
     field public static final java.lang.String DEFERRED_SNIPPETING_KEY = "deferred_snippeting";
     field public static final java.lang.String SNIPPET = "snippet";
-    field public static final java.lang.String SNIPPET_ARGS_PARAM_KEY = "snippet_args";
   }
 
   public static final class ContactsContract.Settings implements android.provider.ContactsContract.SettingsColumns {
@@ -27565,12 +27565,12 @@
 
   public abstract class CallVideoClient {
     ctor protected CallVideoClient();
-    method public abstract void onCallSessionEvent(int);
-    method public abstract void onCameraCapabilitiesChange(android.telecomm.CallCameraCapabilities);
+    method public abstract void onHandleCallSessionEvent(int);
+    method public abstract void onHandleCameraCapabilitiesChange(android.telecomm.CallCameraCapabilities);
     method public abstract void onReceiveSessionModifyRequest(android.telecomm.VideoCallProfile);
     method public abstract void onReceiveSessionModifyResponse(int, android.telecomm.VideoCallProfile, android.telecomm.VideoCallProfile);
     method public abstract void onUpdateCallDataUsage(int);
-    method public abstract void onUpdatedPeerDimensions(int, int);
+    method public abstract void onUpdatePeerDimensions(int, int);
     field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
     field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
     field public static final int SESSION_EVENT_TX_START = 3; // 0x3
@@ -27582,16 +27582,17 @@
 
   public abstract class CallVideoProvider {
     ctor protected CallVideoProvider();
-    method public abstract void requestCallDataUsage();
-    method public abstract void requestCameraCapabilities();
-    method public abstract void sendSessionModifyRequest(android.telecomm.VideoCallProfile);
-    method public abstract void sendSessionModifyResponse(android.telecomm.VideoCallProfile);
-    method public abstract void setCamera(java.lang.String);
-    method public abstract void setDeviceOrientation(int);
-    method public abstract void setDisplaySurface(android.view.Surface);
-    method public abstract void setPauseImage(java.lang.String);
-    method public abstract void setPreviewSurface(android.view.Surface);
-    method public abstract void setZoom(float);
+    method public abstract void onRequestCallDataUsage();
+    method public abstract void onRequestCameraCapabilities();
+    method public abstract void onSendSessionModifyRequest(android.telecomm.VideoCallProfile);
+    method public abstract void onSendSessionModifyResponse(android.telecomm.VideoCallProfile);
+    method public abstract void onSetCallVideoClient(android.telecomm.RemoteCallVideoClient);
+    method public abstract void onSetCamera(java.lang.String);
+    method public abstract void onSetDeviceOrientation(int);
+    method public abstract void onSetDisplaySurface(android.view.Surface);
+    method public abstract void onSetPauseImage(java.lang.String);
+    method public abstract void onSetPreviewSurface(android.view.Surface);
+    method public abstract void onSetZoom(float);
   }
 
   public abstract class Connection {
@@ -27777,9 +27778,29 @@
     method protected abstract void updateCall(android.telecomm.InCallCall);
   }
 
+  public class RemoteCallVideoClient implements android.os.IBinder.DeathRecipient {
+    method public void binderDied();
+    method public void handleCallSessionEvent(int) throws android.os.RemoteException;
+    method public void handleCameraCapabilitiesChange(android.telecomm.CallCameraCapabilities) throws android.os.RemoteException;
+    method public void receiveSessionModifyRequest(android.telecomm.VideoCallProfile) throws android.os.RemoteException;
+    method public void receiveSessionModifyResponse(int, android.telecomm.VideoCallProfile, android.telecomm.VideoCallProfile) throws android.os.RemoteException;
+    method public void updateCallDataUsage(int) throws android.os.RemoteException;
+    method public void updatePeerDimensions(int, int) throws android.os.RemoteException;
+  }
+
   public class RemoteCallVideoProvider implements android.os.IBinder.DeathRecipient {
     method public void binderDied();
+    method public void onSetPauseImage(java.lang.String) throws android.os.RemoteException;
+    method public void requestCallDataUsage() throws android.os.RemoteException;
+    method public void requestCameraCapabilities() throws android.os.RemoteException;
+    method public void sendSessionModifyRequest(android.telecomm.VideoCallProfile) throws android.os.RemoteException;
+    method public void sendSessionModifyResponse(android.telecomm.VideoCallProfile) throws android.os.RemoteException;
+    method public void setCallVideoClient(android.telecomm.CallVideoClient) throws android.os.RemoteException;
     method public void setCamera(java.lang.String) throws android.os.RemoteException;
+    method public void setDeviceOrientation(int) throws android.os.RemoteException;
+    method public void setDisplaySurface(android.view.Surface) throws android.os.RemoteException;
+    method public void setPreviewSurface(android.view.Surface) throws android.os.RemoteException;
+    method public void setZoom(float) throws android.os.RemoteException;
   }
 
   public final class RemoteConnection {
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index d33b14a..a8f6539 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -45,6 +45,7 @@
     private static final String TAG = "EnterTransitionCoordinator";
 
     private static final long MAX_WAIT_MS = 1000;
+    private static final int MIN_ANIMATION_FRAMES = 2;
 
     private boolean mSharedElementTransitionStarted;
     private Activity mActivity;
@@ -280,9 +281,21 @@
         setOriginalImageViewState(originalImageViewState);
 
         if (mResultReceiver != null) {
-            mResultReceiver.send(MSG_HIDE_SHARED_ELEMENTS, null);
+            // We can't trust that the view will disappear on the same frame that the shared
+            // element appears here. Assure that we get at least 2 frames for double-buffering.
+            getDecor().postOnAnimation(new Runnable() {
+                int mAnimations;
+                @Override
+                public void run() {
+                    if (mAnimations++ < MIN_ANIMATION_FRAMES) {
+                        getDecor().postOnAnimation(this);
+                    } else {
+                        mResultReceiver.send(MSG_HIDE_SHARED_ELEMENTS, null);
+                        mResultReceiver = null; // all done sending messages.
+                    }
+                }
+            });
         }
-        mResultReceiver = null; // all done sending messages.
     }
 
     @Override
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 49f2a5d..ba34184 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -29,6 +29,7 @@
 import android.transition.TransitionManager;
 import android.util.ArrayMap;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewGroupOverlay;
 import android.view.ViewTreeObserver;
 
@@ -65,8 +66,6 @@
 
     private Bundle mExitSharedElementBundle;
 
-    private ArrayList<View> mSharedElementSnapshots;
-
     public ExitTransitionCoordinator(Activity activity, ArrayList<String> names,
             ArrayList<String> accepted, ArrayList<View> mapped, boolean isReturning) {
         super(activity.getWindow(), names, getListener(activity, isReturning),
@@ -131,17 +130,14 @@
         Transition transition = getSharedElementExitTransition();
         final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
                 mSharedElementNames);
-        mSharedElementSnapshots = createSnapshots(mExitSharedElementBundle, mSharedElementNames);
         transition.addListener(new Transition.TransitionListenerAdapter() {
             @Override
             public void onTransitionEnd(Transition transition) {
                 transition.removeListener(this);
-                setViewVisibility(mSharedElements, View.INVISIBLE);
-                ViewGroupOverlay overlay = getDecor().getOverlay();
-                if (mSharedElementSnapshots != null) {
-                    for (int i = 0; i < mSharedElementSnapshots.size(); i++) {
-                        overlay.add(mSharedElementSnapshots.get(i));
-                    }
+                int count = mSharedElements.size();
+                for (int i = 0; i < count; i++) {
+                    View sharedElement = mSharedElements.get(i);
+                    ((ViewGroup)sharedElement.getParent()).suppressLayout(true);
                 }
             }
         });
@@ -158,28 +154,10 @@
         getDecor().invalidate();
     }
 
-    private static ArrayList<View> copySnapshots(ArrayList<View> snapshots) {
-        ArrayList<View> copy = new ArrayList<View>(snapshots.size());
-        for (int i = 0; i < snapshots.size(); i++) {
-            View view = snapshots.get(i);
-            View viewCopy = new View(view.getContext());
-            viewCopy.setBackground(view.getBackground());
-            copy.add(viewCopy);
-        }
-        return copy;
-    }
-
     private void hideSharedElements() {
         if (!mIsHidden) {
             setViewVisibility(mSharedElements, View.INVISIBLE);
         }
-        if (mSharedElementSnapshots != null) {
-            ViewGroupOverlay overlay = getDecor().getOverlay();
-            for (int i = 0; i < mSharedElementSnapshots.size(); i++) {
-                overlay.remove(mSharedElementSnapshots.get(i));
-            }
-            mSharedElementSnapshots = null;
-        }
         finishIfNecessary();
     }
 
@@ -360,7 +338,8 @@
     }
 
     private void finishIfNecessary() {
-        if (mIsReturning && mExitNotified && mActivity != null && mSharedElementSnapshots == null) {
+        if (mIsReturning && mExitNotified && mActivity != null && (mSharedElements.isEmpty() ||
+                mSharedElements.get(0).getVisibility() == View.INVISIBLE)) {
             finish();
         }
         if (!mIsReturning && mExitNotified) {
@@ -382,7 +361,6 @@
             mBackgroundAnimator = null;
         }
         mExitSharedElementBundle = null;
-        mSharedElementSnapshots = null;
         clearState();
     }
 
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 64d80a0..a94bc41 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -306,6 +306,11 @@
     public static final String ACTION_UUID =
             "android.bluetooth.device.action.UUID";
 
+    /** @hide */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_MAS_INSTANCE =
+            "android.bluetooth.device.action.MAS_INSTANCE";
+
     /**
      * Broadcast Action: Indicates a failure to retrieve the name of a remote
      * device.
@@ -522,14 +527,17 @@
      * Prefer BR/EDR transport for GATT connections to remote dual-mode devices
      * @hide
      */
-   public static final int TRANSPORT_BREDR = 1;
+    public static final int TRANSPORT_BREDR = 1;
 
     /**
      * Prefer LE transport for GATT connections to remote dual-mode devices
      * @hide
      */
-   public static final int TRANSPORT_LE = 2;
+    public static final int TRANSPORT_LE = 2;
 
+    /** @hide */
+    public static final String EXTRA_MAS_INSTANCE =
+        "android.bluetooth.device.extra.MAS_INSTANCE";
 
     /**
      * Lazy initialization. Guaranteed final after first object constructed, or
@@ -995,6 +1003,18 @@
             return false;
     }
 
+     /** @hide */
+     public boolean fetchMasInstances() {
+         if (sService == null) {
+             Log.e(TAG, "BT not enabled. Cannot query remote device for MAS instances");
+             return false;
+         }
+         try {
+             return sService.fetchRemoteMasInstances(this);
+         } catch (RemoteException e) {Log.e(TAG, "", e);}
+         return false;
+     }
+
     /** @hide */
     public int getServiceChannel(ParcelUuid uuid) {
         //TODO(BT)
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 2e993c9d..fbbc2f7 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -32,12 +32,12 @@
  * Public API for the Bluetooth GATT Profile server role.
  *
  * <p>This class provides Bluetooth GATT server role functionality,
- * allowing applications to create and advertise Bluetooth Smart services
- * and characteristics.
+ * allowing applications to create Bluetooth Smart services and
+ * characteristics.
  *
  * <p>BluetoothGattServer is a proxy object for controlling the Bluetooth Service
- * via IPC.  Use {@link BluetoothAdapter#getProfileProxy} to get the
- * BluetoothGatt proxy object.
+ * via IPC.  Use {@link BluetoothManager#openGattServer} to get an instance
+ * of this class.
  */
 public final class BluetoothGattServer implements BluetoothProfile {
     private static final String TAG = "BluetoothGattServer";
@@ -545,7 +545,7 @@
     /**
      * Add a service to the list of services to be hosted.
      *
-     * <p>Once a service has been addded to the the list, the service and it's
+     * <p>Once a service has been addded to the the list, the service and its
      * included characteristics will be provided by the local device.
      *
      * <p>If the local device has already exposed services when this function
diff --git a/core/java/android/bluetooth/BluetoothMasInstance.java b/core/java/android/bluetooth/BluetoothMasInstance.java
new file mode 100644
index 0000000..4459e2c
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothMasInstance.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public final class BluetoothMasInstance implements Parcelable {
+    private final int mId;
+    private final String mName;
+    private final int mChannel;
+    private final int mMsgTypes;
+
+    public BluetoothMasInstance(int id, String name, int channel, int msgTypes) {
+        mId = id;
+        mName = name;
+        mChannel = channel;
+        mMsgTypes = msgTypes;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof BluetoothMasInstance) {
+            return mId == ((BluetoothMasInstance)o).mId;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return mId + (mChannel << 8) + (mMsgTypes << 16);
+    }
+
+    @Override
+    public String toString() {
+        return Integer.toString(mId) + ":" + mName + ":" + mChannel + ":" +
+                Integer.toHexString(mMsgTypes);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<BluetoothMasInstance> CREATOR =
+            new Parcelable.Creator<BluetoothMasInstance>() {
+        public BluetoothMasInstance createFromParcel(Parcel in) {
+            return new BluetoothMasInstance(in.readInt(), in.readString(),
+                    in.readInt(), in.readInt());
+        }
+        public BluetoothMasInstance[] newArray(int size) {
+            return new BluetoothMasInstance[size];
+        }
+    };
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mId);
+        out.writeString(mName);
+        out.writeInt(mChannel);
+        out.writeInt(mMsgTypes);
+    }
+
+    public static final class MessageType {
+        public static final int EMAIL    = 0x01;
+        public static final int SMS_GSM  = 0x02;
+        public static final int SMS_CDMA = 0x04;
+        public static final int MMS      = 0x08;
+    }
+
+    public int getId() {
+        return mId;
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    public int getChannel() {
+        return mChannel;
+    }
+
+    public int getMsgTypes() {
+        return mMsgTypes;
+    }
+
+    public boolean msgSupported(int msg) {
+        return (mMsgTypes & msg) != 0;
+    }
+}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index a45c6b8..df6037e 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -67,6 +67,7 @@
     int getRemoteClass(in BluetoothDevice device);
     ParcelUuid[] getRemoteUuids(in BluetoothDevice device);
     boolean fetchRemoteUuids(in BluetoothDevice device);
+    boolean fetchRemoteMasInstances(in BluetoothDevice device);
 
     boolean setPin(in BluetoothDevice device, boolean accept, int len, in byte[] pinCode);
     boolean setPasskey(in BluetoothDevice device, boolean accept, int len, in byte[]
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index df6057e..1129c9e 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -31,11 +31,15 @@
 
     /** Control UID policies. */
     void setUidPolicy(int uid, int policy);
+    void addUidPolicy(int uid, int policy);
+    void removeUidPolicy(int uid, int policy);
     int getUidPolicy(int uid);
     int[] getUidsWithPolicy(int policy);
 
     boolean isUidForeground(int uid);
 
+    int[] getPowerSaveAppIdWhitelist();
+
     void registerListener(INetworkPolicyListener listener);
     void unregisterListener(INetworkPolicyListener listener);
 
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 2cd1f9b..a8e7757 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -45,6 +45,8 @@
     public static final int POLICY_NONE = 0x0;
     /** Reject network usage on metered networks when application in background. */
     public static final int POLICY_REJECT_METERED_BACKGROUND = 0x1;
+    /** Allow network use (metered or not) in the background in battery save mode. */
+    public static final int POLICY_ALLOW_BACKGROUND_BATTERY_SAVE = 0x2;
 
     /** All network traffic should be allowed. */
     public static final int RULE_ALLOW_ALL = 0x0;
@@ -76,7 +78,7 @@
      * Set policy flags for specific UID.
      *
      * @param policy {@link #POLICY_NONE} or combination of flags like
-     *            {@link #POLICY_REJECT_METERED_BACKGROUND}.
+     * {@link #POLICY_REJECT_METERED_BACKGROUND}, {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
      */
     public void setUidPolicy(int uid, int policy) {
         try {
@@ -85,6 +87,30 @@
         }
     }
 
+    /**
+     * Add policy flags for specific UID.  The given policy bits will be set for
+     * the uid.  Policy flags may be either
+     * {@link #POLICY_REJECT_METERED_BACKGROUND} or {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
+     */
+    public void addUidPolicy(int uid, int policy) {
+        try {
+            mService.addUidPolicy(uid, policy);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Clear/remove policy flags for specific UID.  The given policy bits will be set for
+     * the uid.  Policy flags may be either
+     * {@link #POLICY_REJECT_METERED_BACKGROUND} or {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
+     */
+    public void removeUidPolicy(int uid, int policy) {
+        try {
+            mService.removeUidPolicy(uid, policy);
+        } catch (RemoteException e) {
+        }
+    }
+
     public int getUidPolicy(int uid) {
         try {
             return mService.getUidPolicy(uid);
@@ -101,6 +127,14 @@
         }
     }
 
+    public int[] getPowerSaveAppIdWhitelist() {
+        try {
+            return mService.getPowerSaveAppIdWhitelist();
+        } catch (RemoteException e) {
+            return new int[0];
+        }
+    }
+
     public void registerListener(INetworkPolicyListener listener) {
         try {
             mService.registerListener(listener);
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java
index cabda5d..34568c2 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.java
+++ b/core/java/android/nfc/cardemulation/AidGroup.java
@@ -16,7 +16,7 @@
  * The AidGroup class represents a group of Application Identifiers (AIDs).
  *
  * <p>An instance of this object can be used with
- * {@link CardEmulation#registerAidGroupForService(android.content.ComponentName, AidGroup)}
+ * {@link CardEmulation#registerAidsForService(android.content.ComponentName, String, java.util.List)}
  * to tell the OS which AIDs are handled by your HCE- or SE-based service.
  *
  * <p>The format of AIDs is defined in the ISO/IEC 7816-4 specification. This class
@@ -50,6 +50,11 @@
         if (aids.size() > MAX_NUM_AIDS) {
             throw new IllegalArgumentException("Too many AIDs in AID group.");
         }
+        for (String aid : aids) {
+            if (!ApduServiceInfo.isValidAid(aid)) {
+                throw new IllegalArgumentException("AID " + aid + " is not a valid AID.");
+            }
+        }
         if (isValidCategory(category)) {
             this.category = category;
         } else {
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index f379ee8..930cf11 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -351,20 +351,37 @@
         }
     }
 
+    /**
+     * A valid AID according to ISO/IEC 7816-4:
+     * <ul>
+     * <li>Has >= 5 bytes and <=16 bytes (>=10 hex chars and <= 32 hex chars)
+     * <li>Consist of only hex characters
+     * <li>Additionally, we allow an asterisk at the end, to indicate
+     *     a prefix
+     * </ul>
+     */
     static boolean isValidAid(String aid) {
         if (aid == null)
             return false;
 
-        int aidLength = aid.length();
-        if (aidLength == 0 || (aidLength % 2) != 0) {
-            Log.e(TAG, "AID " + aid + " is not correctly formatted.");
+        // If a prefix AID, the total length must be odd (even # of AID chars + '*')
+        if (aid.endsWith("*") && ((aid.length() % 2) == 0)) {
+            Log.e(TAG, "AID " + aid + " is not a valid AID.");
             return false;
         }
-        // Minimum AID length is 5 bytes, 10 hex chars
-        if (aidLength < 10) {
-            Log.e(TAG, "AID " + aid + " is shorter than 5 bytes.");
+
+        // If not a prefix AID, the total length must be even (even # of AID chars)
+        if (!aid.endsWith("*") && ((aid.length() % 2) != 0)) {
+            Log.e(TAG, "AID " + aid + " is not a valid AID.");
             return false;
         }
+
+        // Verify hex characters
+        if (!aid.matches("[0-9A-Fa-f]{10,32}\\*?")) {
+            Log.e(TAG, "AID " + aid + " is not a valid AID.");
+            return false;
+        }
+
         return true;
     }
 
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index f7d2bfd..21d60c5 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -614,6 +614,7 @@
         public static final int STATE2_VIDEO_ON_FLAG = 1<<30;
         public static final int STATE2_WIFI_RUNNING_FLAG = 1<<29;
         public static final int STATE2_WIFI_ON_FLAG = 1<<28;
+        public static final int STATE2_FLASHLIGHT_FLAG = 1<<27;
 
         public static final int MOST_INTERESTING_STATES2 =
             STATE2_LOW_POWER_FLAG | STATE2_WIFI_ON_FLAG;
@@ -1235,6 +1236,7 @@
         new BitDescription(HistoryItem.STATE2_VIDEO_ON_FLAG, "video", "v"),
         new BitDescription(HistoryItem.STATE2_WIFI_RUNNING_FLAG, "wifi_running", "Wr"),
         new BitDescription(HistoryItem.STATE2_WIFI_ON_FLAG, "wifi", "W"),
+        new BitDescription(HistoryItem.STATE2_FLASHLIGHT_FLAG, "flashlight", "fl"),
         new BitDescription(HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK,
                 HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT, "wifi_signal_strength", "Wss",
                 new String[] { "0", "1", "2", "3", "4" },
@@ -1370,6 +1372,22 @@
      */
     public abstract int getBluetoothStateCount(int bluetoothState, int which);
 
+    /**
+     * Returns the time in microseconds that the flashlight has been on while the device was
+     * running on battery.
+     *
+     * {@hide}
+     */
+    public abstract long getFlashlightOnTime(long elapsedRealtimeUs, int which);
+
+    /**
+     * Returns the number of times that the flashlight has been turned on while the device was
+     * running on battery.
+     *
+     * {@hide}
+     */
+    public abstract long getFlashlightOnCount(int which);
+
     public static final int NETWORK_MOBILE_RX_DATA = 0;
     public static final int NETWORK_MOBILE_TX_DATA = 1;
     public static final int NETWORK_WIFI_RX_DATA = 2;
@@ -1965,6 +1983,9 @@
                     case SCREEN:
                         label="scrn";
                         break;
+                    case FLASHLIGHT:
+                        label="flashlight";
+                        break;
                     case APP:
                         uid = bs.uidObj.getUid();
                         label = "uid";
@@ -2637,6 +2658,10 @@
                         pw.print(prefix); pw.print("    Screen: "); printmAh(pw, bs.value);
                         pw.println();
                         break;
+                    case FLASHLIGHT:
+                        pw.print(prefix); pw.print("    Flashlight: "); printmAh(pw, bs.value);
+                        pw.println();
+                        break;
                     case APP:
                         pw.print(prefix); pw.print("    Uid ");
                         UserHandle.formatUid(pw, bs.uidObj.getUid());
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index b839613..2f061f1 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -36,6 +36,7 @@
 import android.database.DatabaseUtils;
 import android.graphics.Rect;
 import android.net.Uri;
+import android.net.Uri.Builder;
 import android.os.RemoteException;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
@@ -171,13 +172,16 @@
      * A key to a boolean in the "extras" bundle of the cursor.
      * The boolean indicates that the provider did not create a snippet and that the client asking
      * for the snippet should do it (true means the snippeting was deferred to the client).
+     *
+     * @see SearchSnippets
      */
     public static final String DEFERRED_SNIPPETING = "deferred_snippeting";
 
     /**
-     * Key to retrieve the original query on the client side.
+     * Key to retrieve the original deferred snippeting from the cursor on the client side.
      *
-     * @hide
+     * @see SearchSnippets
+     * @see #DEFERRED_SNIPPETING
      */
     public static final String DEFERRED_SNIPPETING_QUERY = "deferred_snippeting_query";
 
@@ -5089,42 +5093,75 @@
     /**
      * Additional column returned by
      * {@link ContactsContract.Contacts#CONTENT_FILTER_URI Contacts.CONTENT_FILTER_URI} explaining
-     * why the filter matched the contact.  Specifically, it contains the data elements that
-     * matched the query.  The overall number of words in the snippet can be capped.
+     * why the filter matched the contact. This column will contain extracts from the contact's
+     * constituent {@link Data Data} items, formatted in a way that indicates the section of the
+     * snippet that matched the filter.
+     *
+     * <p>
+     * The following example searches for all contacts that match the query "presi" and requests
+     * the snippet column as well.
+     * <pre>
+     * Builder builder = Contacts.CONTENT_FILTER_URI.buildUpon();
+     * builder.appendPath("presi");
+     * // Defer snippeting to the client side if possible, for performance reasons.
+     * builder.appendQueryParameter(SearchSnippets.DEFERRED_SNIPPETING_KEY,"1");
+     *
+     * Cursor cursor = getContentResolver().query(builder.build());
+     *
+     * Bundle extras = cursor.getExtras();
+     * if (extras.getBoolean(ContactsContract.DEFERRED_SNIPPETING)) {
+     *     // Do our own snippet formatting.
+     *     // For a contact with the email address (president@organization.com), the snippet
+     *     // column will contain the string "president@organization.com".
+     * } else {
+     *     // The snippet has already been pre-formatted, we can display it as is.
+     *     // For a contact with the email address (president@organization.com), the snippet
+     *     // column will contain the string "[presi]dent@organization.com".
+     * }
+     * </pre>
+     * </p>
      */
-    public static class SearchSnippetColumns {
+    public static class SearchSnippets {
 
         /**
-         * The search snippet constructed according to the SQLite rules, see
-         * http://www.sqlite.org/fts3.html#snippet
+         * The search snippet constructed by SQLite snippeting functionality.
          * <p>
-         * The snippet may contain (parts of) several data elements comprising
-         * the contact.
+         * The snippet may contain (parts of) several data elements belonging to the contact,
+         * with the matching parts optionally surrounded by special characters that indicate the
+         * start and end of matching text.
+         *
+         * For example, if a contact has an address "123 Main Street", using a filter "mai" would
+         * return the formatted snippet "123 [Mai]n street".
+         *
+         * @see <a href="http://www.sqlite.org/fts3.html#snippet">
+         *         http://www.sqlite.org/fts3.html#snippet</a>
          */
         public static final String SNIPPET = "snippet";
 
-
         /**
          * Comma-separated parameters for the generation of the snippet:
          * <ul>
-         * <li>The "start match" text. Default is &lt;b&gt;</li>
-         * <li>The "end match" text. Default is &lt;/b&gt;</li>
-         * <li>The "ellipsis" text. Default is &lt;b&gt;...&lt;/b&gt;</li>
+         * <li>The "start match" text. Default is '['</li>
+         * <li>The "end match" text. Default is ']'</li>
+         * <li>The "ellipsis" text. Default is "..."</li>
          * <li>Maximum number of tokens to include in the snippet. Can be either
          * a positive or a negative number: A positive number indicates how many
          * tokens can be returned in total. A negative number indicates how many
          * tokens can be returned per occurrence of the search terms.</li>
          * </ul>
+         *
+         * @hide
          */
         public static final String SNIPPET_ARGS_PARAM_KEY = "snippet_args";
 
         /**
-         * A key to ask the provider to defer the snippeting to the client if possible.
-         * Value of 1 implies true, 0 implies false when 0 is the default.
+         * The key to ask the provider to defer the formatting of the snippet to the client if
+         * possible, for performance reasons.
+         * A value of 1 indicates true, 0 indicates false. False is the default.
          * When a cursor is returned to the client, it should check for an extra with the name
          * {@link ContactsContract#DEFERRED_SNIPPETING} in the cursor. If it exists, the client
-         * should do its own snippeting. If it doesn't exist, the snippet column in the cursor
-         * should already contain a snippetized string.
+         * should do its own formatting of the snippet. If it doesn't exist, the snippet column
+         * in the cursor should already contain a formatted snippet.
          */
         public static final String DEFERRED_SNIPPETING_KEY = "deferred_snippeting";
     }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d544804b..33b6d6c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7240,9 +7240,6 @@
             if (viewRootImpl != null) {
                 viewRootImpl.setAccessibilityFocus(this, null);
             }
-            Rect rect = (mAttachInfo != null) ? mAttachInfo.mTmpInvalRect : new Rect();
-            getDrawingRect(rect);
-            requestRectangleOnScreen(rect, false);
             invalidate();
             sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
             return true;
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 3f72b4c..4ca5863 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -338,7 +338,8 @@
      * By default, the animator uses the default interpolator for ValueAnimator. Calling this method
      * will cause the declared object to be used instead.
      * 
-     * @param interpolator The TimeInterpolator to be used for ensuing property animations.
+     * @param interpolator The TimeInterpolator to be used for ensuing property animations. A value
+     * of <code>null</code> will result in linear interpolation.
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
diff --git a/core/java/android/view/ViewPropertyAnimatorRT.java b/core/java/android/view/ViewPropertyAnimatorRT.java
index 8b4277a..31b360c 100644
--- a/core/java/android/view/ViewPropertyAnimatorRT.java
+++ b/core/java/android/view/ViewPropertyAnimatorRT.java
@@ -18,6 +18,8 @@
 
 import android.animation.TimeInterpolator;
 import android.view.ViewPropertyAnimator.NameValuesHolder;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
 
 import com.android.internal.view.animation.FallbackLUTInterpolator;
 
@@ -29,6 +31,8 @@
  */
 class ViewPropertyAnimatorRT {
 
+    private static final Interpolator sLinearInterpolator = new LinearInterpolator();
+
     private final View mView;
 
     private RenderNodeAnimator mAnimators[] = new RenderNodeAnimator[RenderNodeAnimator.LAST_VALUE + 1];
@@ -65,6 +69,10 @@
         long startDelay = parent.getStartDelay();
         long duration = parent.getDuration();
         TimeInterpolator interpolator = parent.getInterpolator();
+        if (interpolator == null) {
+            // Documented to be LinearInterpolator in ValueAnimator.setInterpolator
+            interpolator = sLinearInterpolator;
+        }
         if (!RenderNodeAnimator.isNativeInterpolator(interpolator)) {
             interpolator = new FallbackLUTInterpolator(interpolator, duration);
         }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 8567bed..5743882 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -37,8 +37,6 @@
 import android.inputmethodservice.ExtractEditText;
 import android.os.AsyncTask;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
@@ -97,6 +95,7 @@
 import android.util.TypedValue;
 import android.view.AccessibilityIterators.TextSegmentIterator;
 import android.view.ActionMode;
+import android.view.Choreographer;
 import android.view.DragEvent;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
@@ -9088,26 +9087,22 @@
         }
     }
 
-    private static final class Marquee extends Handler {
+    private static final class Marquee {
         // TODO: Add an option to configure this
         private static final float MARQUEE_DELTA_MAX = 0.07f;
         private static final int MARQUEE_DELAY = 1200;
         private static final int MARQUEE_RESTART_DELAY = 1200;
-        private static final int MARQUEE_RESOLUTION = 1000 / 30;
-        private static final int MARQUEE_PIXELS_PER_SECOND = 30;
+        private static final int MARQUEE_DP_PER_SECOND = 30;
 
         private static final byte MARQUEE_STOPPED = 0x0;
         private static final byte MARQUEE_STARTING = 0x1;
         private static final byte MARQUEE_RUNNING = 0x2;
 
-        private static final int MESSAGE_START = 0x1;
-        private static final int MESSAGE_TICK = 0x2;
-        private static final int MESSAGE_RESTART = 0x3;
-
         private final WeakReference<TextView> mView;
+        private final Choreographer mChoreographer;
 
         private byte mStatus = MARQUEE_STOPPED;
-        private final float mScrollUnit;
+        private final float mPixelsPerSecond;
         private float mMaxScroll;
         private float mMaxFadeScroll;
         private float mGhostStart;
@@ -9116,49 +9111,62 @@
         private int mRepeatLimit;
 
         private float mScroll;
+        private long mLastAnimationMs;
 
         Marquee(TextView v) {
             final float density = v.getContext().getResources().getDisplayMetrics().density;
-            mScrollUnit = (MARQUEE_PIXELS_PER_SECOND * density) / MARQUEE_RESOLUTION;
+            mPixelsPerSecond = MARQUEE_DP_PER_SECOND * density;
             mView = new WeakReference<TextView>(v);
+            mChoreographer = Choreographer.getInstance();
         }
 
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MESSAGE_START:
-                    mStatus = MARQUEE_RUNNING;
-                    tick();
-                    break;
-                case MESSAGE_TICK:
-                    tick();
-                    break;
-                case MESSAGE_RESTART:
-                    if (mStatus == MARQUEE_RUNNING) {
-                        if (mRepeatLimit >= 0) {
-                            mRepeatLimit--;
-                        }
-                        start(mRepeatLimit);
-                    }
-                    break;
+        private Choreographer.FrameCallback mTickCallback = new Choreographer.FrameCallback() {
+            @Override
+            public void doFrame(long frameTimeNanos) {
+                tick();
             }
-        }
+        };
+
+        private Choreographer.FrameCallback mStartCallback = new Choreographer.FrameCallback() {
+            @Override
+            public void doFrame(long frameTimeNanos) {
+                mStatus = MARQUEE_RUNNING;
+                mLastAnimationMs = mChoreographer.getFrameTime();
+                tick();
+            }
+        };
+
+        private Choreographer.FrameCallback mRestartCallback = new Choreographer.FrameCallback() {
+            @Override
+            public void doFrame(long frameTimeNanos) {
+                if (mStatus == MARQUEE_RUNNING) {
+                    if (mRepeatLimit >= 0) {
+                        mRepeatLimit--;
+                    }
+                    start(mRepeatLimit);
+                }
+            }
+        };
 
         void tick() {
             if (mStatus != MARQUEE_RUNNING) {
                 return;
             }
 
-            removeMessages(MESSAGE_TICK);
+            mChoreographer.removeFrameCallback(mTickCallback);
 
             final TextView textView = mView.get();
             if (textView != null && (textView.isFocused() || textView.isSelected())) {
-                mScroll += mScrollUnit;
+                long currentMs = mChoreographer.getFrameTime();
+                long deltaMs = currentMs - mLastAnimationMs;
+                mLastAnimationMs = currentMs;
+                float deltaPx = deltaMs / 1000f * mPixelsPerSecond;
+                mScroll += deltaPx;
                 if (mScroll > mMaxScroll) {
                     mScroll = mMaxScroll;
-                    sendEmptyMessageDelayed(MESSAGE_RESTART, MARQUEE_RESTART_DELAY);
+                    mChoreographer.postFrameCallbackDelayed(mRestartCallback, MARQUEE_DELAY);
                 } else {
-                    sendEmptyMessageDelayed(MESSAGE_TICK, MARQUEE_RESOLUTION);
+                    mChoreographer.postFrameCallback(mTickCallback);
                 }
                 textView.invalidate();
             }
@@ -9166,9 +9174,9 @@
 
         void stop() {
             mStatus = MARQUEE_STOPPED;
-            removeMessages(MESSAGE_START);
-            removeMessages(MESSAGE_RESTART);
-            removeMessages(MESSAGE_TICK);
+            mChoreographer.removeFrameCallback(mStartCallback);
+            mChoreographer.removeFrameCallback(mRestartCallback);
+            mChoreographer.removeFrameCallback(mTickCallback);
             resetScroll();
         }
 
@@ -9199,7 +9207,7 @@
                 mMaxFadeScroll = mGhostStart + lineWidth + lineWidth;
 
                 textView.invalidate();
-                sendEmptyMessageDelayed(MESSAGE_START, MARQUEE_DELAY);
+                mChoreographer.postFrameCallback(mStartCallback);
             }
         }
 
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 7a9137b..ae9b515 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -58,6 +58,8 @@
 
     void noteVibratorOn(int uid, long durationMillis);
     void noteVibratorOff(int uid);
+    void noteFlashlightOn();
+    void noteFlashlightOff();
     void noteStartGps(int uid);
     void noteStopGps(int uid);
     void noteScreenState(int state);
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index 6ca24d7..247c8fe 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -54,6 +54,7 @@
         PHONE,
         WIFI,
         BLUETOOTH,
+        FLASHLIGHT,
         SCREEN,
         APP,
         USER,
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 7ff949e..469aa6f 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -706,6 +706,15 @@
         }
     }
 
+    private void addFlashlightUsage() {
+        long flashlightOnTimeMs = mStats.getFlashlightOnTime(mRawRealtime, mStatsType) / 1000;
+        double flashlightPower = flashlightOnTimeMs
+                * mPowerProfile.getAveragePower(PowerProfile.POWER_FLASHLIGHT) / (60*60*1000);
+        if (flashlightPower != 0) {
+            addEntry(BatterySipper.DrainType.FLASHLIGHT, flashlightOnTimeMs, flashlightPower);
+        }
+    }
+
     private void addUserUsage() {
         for (int i=0; i<mUserSippers.size(); i++) {
             final int userId = mUserSippers.keyAt(i);
@@ -760,6 +769,7 @@
         addUserUsage();
         addPhoneUsage();
         addScreenUsage();
+        addFlashlightUsage();
         addWiFiUsage();
         addBluetoothUsage();
         addIdleUsage(); // Not including cellular idle power
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 02e4b3f..49d11dc 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -89,7 +89,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 107 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 108 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -260,6 +260,9 @@
     boolean mVideoOn;
     StopwatchTimer mVideoOnTimer;
 
+    boolean mFlashlightOn;
+    StopwatchTimer mFlashlightOnTimer;
+
     int mPhoneSignalStrengthBin = -1;
     int mPhoneSignalStrengthBinRaw = -1;
     final StopwatchTimer[] mPhoneSignalStrengthsTimer = 
@@ -3177,6 +3180,32 @@
         getUidStatsLocked(uid).noteVibratorOffLocked();
     }
 
+    public void noteFlashlightOnLocked() {
+        if (!mFlashlightOn) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHistoryCur.states2 |= HistoryItem.STATE2_FLASHLIGHT_FLAG;
+            if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight on to: "
+                    + Integer.toHexString(mHistoryCur.states));
+            addHistoryRecordLocked(elapsedRealtime, uptime);
+            mFlashlightOn = true;
+            mFlashlightOnTimer.startRunningLocked(elapsedRealtime);
+        }
+    }
+
+    public void noteFlashlightOffLocked() {
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
+        final long uptime = SystemClock.uptimeMillis();
+        if (mFlashlightOn) {
+            mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG;
+            if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: "
+                    + Integer.toHexString(mHistoryCur.states));
+            addHistoryRecordLocked(elapsedRealtime, uptime);
+            mFlashlightOn = false;
+            mFlashlightOnTimer.stopRunningLocked(elapsedRealtime);
+        }
+    }
+
     public void noteWifiRunningLocked(WorkSource ws) {
         if (!mGlobalWifiRunning) {
             final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -3682,6 +3711,14 @@
         return mBluetoothStateTimer[bluetoothState].getCountLocked(which);
     }
 
+    @Override public long getFlashlightOnTime(long elapsedRealtimeUs, int which) {
+        return mFlashlightOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
+    }
+
+    @Override public long getFlashlightOnCount(int which) {
+        return mFlashlightOnTimer.getCountLocked(which);
+    }
+
     @Override
     public long getNetworkActivityBytes(int type, int which) {
         if (type >= 0 && type < mNetworkByteActivityCounters.length) {
@@ -5681,6 +5718,7 @@
         }
         mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
         mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
+        mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase);
         mOnBattery = mOnBatteryInternal = false;
         long uptime = SystemClock.uptimeMillis() * 1000;
         long realtime = SystemClock.elapsedRealtime() * 1000;
@@ -5930,6 +5968,7 @@
         mPhoneOnTimer.reset(false);
         mAudioOnTimer.reset(false);
         mVideoOnTimer.reset(false);
+        mFlashlightOnTimer.reset(false);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             mPhoneSignalStrengthsTimer[i].reset(false);
         }
@@ -7124,6 +7163,8 @@
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].readSummaryFromParcelLocked(in);
         }
+        mFlashlightOn = false;
+        mFlashlightOnTimer.readSummaryFromParcelLocked(in);
 
         int NKW = in.readInt();
         if (NKW > 10000) {
@@ -7381,6 +7422,7 @@
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
+        mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
 
         out.writeInt(mKernelWakelockStats.size());
         for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
@@ -7667,6 +7709,8 @@
         mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
         mVideoOn = false;
         mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
+        mFlashlightOn = false;
+        mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase, in);
         mDischargeUnplugLevel = in.readInt();
         mDischargePlugLevel = in.readInt();
         mDischargeCurrentLevel = in.readInt();
@@ -7798,6 +7842,7 @@
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].writeToParcel(out, uSecRealtime);
         }
+        mFlashlightOnTimer.writeToParcel(out, uSecRealtime);
         out.writeInt(mDischargeUnplugLevel);
         out.writeInt(mDischargePlugLevel);
         out.writeInt(mDischargeCurrentLevel);
@@ -7931,6 +7976,8 @@
                 pr.println("*** Bluetooth active type #" + i + ":");
                 mBluetoothStateTimer[i].logState(pr, "  ");
             }
+            pr.println("*** Flashlight timer:");
+            mFlashlightOnTimer.logState(pr, "  ");
         }
         super.dumpLocked(context, pw, flags, reqUid, histStart);
     }
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 94750d3..b3bafa1 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -133,6 +133,11 @@
      */
     public static final String POWER_VIDEO = "dsp.video";
 
+    /**
+     * Power consumption when camera flashlight is on.
+     */
+    public static final String POWER_FLASHLIGHT = "camera.flashlight";
+
     public static final String POWER_CPU_SPEEDS = "cpu.speeds";
 
     /**
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index c139c9d..f7886d3 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -1,6 +1,7 @@
 #include "SkBitmap.h"
 #include "SkPixelRef.h"
 #include "SkImageEncoder.h"
+#include "SkImageInfo.h"
 #include "SkColorPriv.h"
 #include "GraphicsJNI.h"
 #include "SkDither.h"
@@ -97,13 +98,14 @@
 }
 
 // can return NULL
-static FromColorProc ChooseFromColorProc(SkBitmap::Config config, bool isPremultiplied) {
-    switch (config) {
-        case SkBitmap::kARGB_8888_Config:
-            return isPremultiplied ? FromColor_D32 : FromColor_D32_Raw;
-        case SkBitmap::kARGB_4444_Config:
-            return isPremultiplied ? FromColor_D4444 : FromColor_D4444_Raw;
-        case SkBitmap::kRGB_565_Config:
+static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) {
+    switch (bitmap.colorType()) {
+        case kN32_SkColorType:
+            return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D32 : FromColor_D32_Raw;
+        case kARGB_4444_SkColorType:
+            return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D4444 :
+                    FromColor_D4444_Raw;
+        case kRGB_565_SkColorType:
             return FromColor_D565;
         default:
             break;
@@ -112,11 +114,10 @@
 }
 
 bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
-        int x, int y, int width, int height,
-        const SkBitmap& dstBitmap, bool isPremultiplied) {
+        int x, int y, int width, int height, const SkBitmap& dstBitmap) {
     SkAutoLockPixels alp(dstBitmap);
     void* dst = dstBitmap.getPixels();
-    FromColorProc proc = ChooseFromColorProc(dstBitmap.config(), isPremultiplied);
+    FromColorProc proc = ChooseFromColorProc(dstBitmap);
 
     if (NULL == dst || NULL == proc) {
         return false;
@@ -257,22 +258,46 @@
 }
 
 // can return NULL
-static ToColorProc ChooseToColorProc(const SkBitmap& src, bool isPremultiplied) {
+static ToColorProc ChooseToColorProc(const SkBitmap& src) {
     switch (src.colorType()) {
         case kN32_SkColorType:
-            if (src.isOpaque()) return ToColor_S32_Opaque;
-            return isPremultiplied ? ToColor_S32_Alpha : ToColor_S32_Raw;
+            switch (src.alphaType()) {
+                case kOpaque_SkAlphaType:
+                    return ToColor_S32_Opaque;
+                case kPremul_SkAlphaType:
+                    return ToColor_S32_Alpha;
+                case kUnpremul_SkAlphaType:
+                    return ToColor_S32_Raw;
+                default:
+                    return NULL;
+            }
         case kARGB_4444_SkColorType:
-            if (src.isOpaque()) return ToColor_S4444_Opaque;
-            return isPremultiplied ? ToColor_S4444_Alpha : ToColor_S4444_Raw;
+            switch (src.alphaType()) {
+                case kOpaque_SkAlphaType:
+                    return ToColor_S4444_Opaque;
+                case kPremul_SkAlphaType:
+                    return ToColor_S4444_Alpha;
+                case kUnpremul_SkAlphaType:
+                    return ToColor_S4444_Raw;
+                default:
+                    return NULL;
+            }
         case kRGB_565_SkColorType:
             return ToColor_S565;
         case kIndex_8_SkColorType:
             if (src.getColorTable() == NULL) {
                 return NULL;
             }
-            if (src.isOpaque()) return ToColor_SI8_Opaque;
-            return isPremultiplied ? ToColor_SI8_Raw : ToColor_SI8_Alpha;
+            switch (src.alphaType()) {
+                case kOpaque_SkAlphaType:
+                    return ToColor_SI8_Opaque;
+                case kPremul_SkAlphaType:
+                    return ToColor_SI8_Alpha;
+                case kUnpremul_SkAlphaType:
+                    return ToColor_SI8_Raw;
+                default:
+                    return NULL;
+            }
         default:
             break;
     }
@@ -315,7 +340,7 @@
 
     if (jColors != NULL) {
         GraphicsJNI::SetPixels(env, jColors, offset, stride,
-                0, 0, width, height, bitmap, true);
+                0, 0, width, height, bitmap);
     }
 
     return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff,
@@ -477,20 +502,38 @@
     return static_cast<jint>(bitmap->getGenerationID());
 }
 
+static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    if (bitmap->alphaType() == kPremul_SkAlphaType) {
+        return JNI_TRUE;
+    }
+    return JNI_FALSE;
+}
+
 static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
     return !bitmap->isOpaque() ? JNI_TRUE : JNI_FALSE;
 }
 
-static void Bitmap_setAlphaAndPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
-                                            jboolean hasAlpha, jboolean isPremul) {
+static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
+        jboolean hasAlpha, jboolean requestPremul) {
     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
-    if (!hasAlpha) {
-        bitmap->setAlphaType(kOpaque_SkAlphaType);
-    } else if (isPremul) {
-        bitmap->setAlphaType(kPremul_SkAlphaType);
+    if (hasAlpha) {
+        bitmap->setAlphaType(requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
     } else {
-        bitmap->setAlphaType(kUnpremul_SkAlphaType);
+        bitmap->setAlphaType(kOpaque_SkAlphaType);
+    }
+}
+
+static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
+        jboolean isPremul) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    if (!bitmap->isOpaque()) {
+        if (isPremul) {
+            bitmap->setAlphaType(kPremul_SkAlphaType);
+        } else {
+            bitmap->setAlphaType(kUnpremul_SkAlphaType);
+        }
     }
 }
 
@@ -661,11 +704,11 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
-        jint x, jint y, jboolean isPremultiplied) {
+        jint x, jint y) {
     const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
     SkAutoLockPixels alp(*bitmap);
 
-    ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
+    ToColorProc proc = ChooseToColorProc(*bitmap);
     if (NULL == proc) {
         return 0;
     }
@@ -681,11 +724,11 @@
 
 static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
         jintArray pixelArray, jint offset, jint stride,
-        jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
+        jint x, jint y, jint width, jint height) {
     const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
     SkAutoLockPixels alp(*bitmap);
 
-    ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
+    ToColorProc proc = ChooseToColorProc(*bitmap);
     if (NULL == proc) {
         return;
     }
@@ -708,7 +751,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
-        jint x, jint y, jint colorHandle, jboolean isPremultiplied) {
+        jint x, jint y, jint colorHandle) {
     const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
     SkColor color = static_cast<SkColor>(colorHandle);
     SkAutoLockPixels alp(*bitmap);
@@ -716,7 +759,7 @@
         return;
     }
 
-    FromColorProc proc = ChooseFromColorProc(bitmap->config(), isPremultiplied);
+    FromColorProc proc = ChooseFromColorProc(*bitmap);
     if (NULL == proc) {
         return;
     }
@@ -727,10 +770,10 @@
 
 static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
         jintArray pixelArray, jint offset, jint stride,
-        jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
+        jint x, jint y, jint width, jint height) {
     const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
     GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
-            x, y, width, height, *bitmap, isPremultiplied);
+            x, y, width, height, *bitmap);
 }
 
 static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
@@ -834,7 +877,9 @@
     {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
     {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
     {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
-    {   "nativeSetAlphaAndPremultiplied", "(JZZ)V", (void*)Bitmap_setAlphaAndPremultiplied},
+    {   "nativeIsPremultiplied",    "(J)Z", (void*)Bitmap_isPremultiplied},
+    {   "nativeSetHasAlpha",        "(JZZ)V", (void*)Bitmap_setHasAlpha},
+    {   "nativeSetPremultiplied",   "(JZ)V", (void*)Bitmap_setPremultiplied},
     {   "nativeHasMipMap",          "(J)Z", (void*)Bitmap_hasMipMap },
     {   "nativeSetHasMipMap",       "(JZ)V", (void*)Bitmap_setHasMipMap },
     {   "nativeCreateFromParcel",
@@ -845,10 +890,10 @@
     {   "nativeExtractAlpha",       "(JJ[I)Landroid/graphics/Bitmap;",
         (void*)Bitmap_extractAlpha },
     {   "nativeGenerationId",       "(J)I", (void*)Bitmap_getGenerationId },
-    {   "nativeGetPixel",           "(JIIZ)I", (void*)Bitmap_getPixel },
-    {   "nativeGetPixels",          "(J[IIIIIIIZ)V", (void*)Bitmap_getPixels },
-    {   "nativeSetPixel",           "(JIIIZ)V", (void*)Bitmap_setPixel },
-    {   "nativeSetPixels",          "(J[IIIIIIIZ)V", (void*)Bitmap_setPixels },
+    {   "nativeGetPixel",           "(JII)I", (void*)Bitmap_getPixel },
+    {   "nativeGetPixels",          "(J[IIIIIII)V", (void*)Bitmap_getPixels },
+    {   "nativeSetPixel",           "(JIII)V", (void*)Bitmap_setPixel },
+    {   "nativeSetPixels",          "(J[IIIIIII)V", (void*)Bitmap_setPixels },
     {   "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
                                             (void*)Bitmap_copyPixelsToBuffer },
     {   "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 3f323ab..6254f3d 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -24,6 +24,7 @@
 #include "SkDeque.h"
 #include "SkDrawFilter.h"
 #include "SkGraphics.h"
+#include <SkImageInfo.h>
 #include "SkPorterDuff.h"
 #include "SkShader.h"
 #include "SkTArray.h"
@@ -699,6 +700,8 @@
                                 jboolean hasAlpha, jlong paintHandle) {
         SkCanvas* canvas = getNativeCanvas(canvasHandle);
         SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+        // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
+        // correct the alphaType to kOpaque_SkAlphaType.
         SkImageInfo info = SkImageInfo::Make(width, height,
                                hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
                                kPremul_SkAlphaType);
@@ -708,7 +711,7 @@
         }
 
         if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride,
-                0, 0, width, height, bitmap, true)) {
+                0, 0, width, height, bitmap)) {
             return;
         }
 
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 7fda3d9..0ad7fd8 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -90,10 +90,11 @@
 
     /** Copy the colors in colors[] to the bitmap, convert to the correct
         format along the way.
+        Whether to use premultiplied pixels is determined by dstBitmap's alphaType.
     */
     static bool SetPixels(JNIEnv* env, jintArray colors, int srcOffset,
             int srcStride, int x, int y, int width, int height,
-            const SkBitmap& dstBitmap, bool isPremultiplied);
+            const SkBitmap& dstBitmap);
 
     static jbyteArray getBitmapStorageObj(SkPixelRef *pixref);
 };
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index b38f5f2..c352398 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -30,6 +30,7 @@
 
 #include <SkBitmap.h>
 #include <SkCanvas.h>
+#include <SkImageInfo.h>
 #include <SkMatrix.h>
 #include <SkPaint.h>
 #include <SkPorterDuff.h>
@@ -376,6 +377,8 @@
 static void android_view_GLES20Canvas_drawBitmapData(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jintArray colors, jint offset, jint stride,
         jfloat left, jfloat top, jint width, jint height, jboolean hasAlpha, jlong paintPtr) {
+    // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
+    // correct the alphaType to kOpaque_SkAlphaType.
     const SkImageInfo info = SkImageInfo::Make(width, height,
                                hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
                                kPremul_SkAlphaType);
@@ -385,7 +388,7 @@
         return;
     }
 
-    if (!GraphicsJNI::SetPixels(env, colors, offset, stride, 0, 0, width, height, *bitmap, true)) {
+    if (!GraphicsJNI::SetPixels(env, colors, offset, stride, 0, 0, width, height, *bitmap)) {
         delete bitmap;
         return;
     }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7db478d..450a889 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -99,6 +99,7 @@
     <protected-broadcast android:name="android.bluetooth.adapter.action.LOCAL_NAME_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.device.action.UUID" />
+    <protected-broadcast android:name="android.bluetooth.device.action.MAS_INSTANCE" />
     <protected-broadcast android:name="android.bluetooth.device.action.ALIAS_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.device.action.FOUND" />
     <protected-broadcast android:name="android.bluetooth.device.action.DISAPPEARED" />
@@ -396,6 +397,15 @@
         android:label="@string/permlab_receiveWapPush"
         android:description="@string/permdesc_receiveWapPush" />
 
+    <!-- Allows an application to monitor incoming Bluetooth MAP messages, to record
+         or perform processing on them. -->
+    <!-- @hide -->
+    <permission android:name="android.permission.RECEIVE_BLUETOOTH_MAP"
+        android:permissionGroup="android.permission-group.MESSAGES"
+        android:protectionLevel="dangerous"
+        android:label="@string/permlab_receiveBluetoothMap"
+        android:description="@string/permdesc_receiveBluetoothMap" />
+
     <!-- =============================================================== -->
     <!-- Permissions for accessing social info (contacts and social) -->
     <!-- =============================================================== -->
diff --git a/core/res/res/anim/progress_indeterminate_rotation_material.xml b/core/res/res/anim/progress_indeterminate_rotation_material.xml
new file mode 100644
index 0000000..5d3ba22
--- /dev/null
+++ b/core/res/res/anim/progress_indeterminate_rotation_material.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:duration="6665"
+    android:interpolator="@android:anim/linear_interpolator"
+    android:propertyName="rotation"
+    android:repeatCount="-1"
+    android:valueFrom="0"
+    android:valueTo="720"
+    android:valueType="floatType" />
\ No newline at end of file
diff --git a/core/res/res/drawable/progress_large_material.xml b/core/res/res/drawable/progress_large_material.xml
index 341d2a9..526f914 100644
--- a/core/res/res/drawable/progress_large_material.xml
+++ b/core/res/res/drawable/progress_large_material.xml
@@ -21,4 +21,8 @@
         android:name="progressBar"
         android:animation="@anim/progress_indeterminate_material" />
 
+    <target
+        android:name="root"
+        android:animation="@anim/progress_indeterminate_rotation_material" />
+
 </animated-vector>
diff --git a/core/res/res/drawable/progress_medium_material.xml b/core/res/res/drawable/progress_medium_material.xml
index 1f2622c..cc35816 100644
--- a/core/res/res/drawable/progress_medium_material.xml
+++ b/core/res/res/drawable/progress_medium_material.xml
@@ -20,4 +20,8 @@
         android:name="progressBar"
         android:animation="@anim/progress_indeterminate_material" />
 
+    <target
+        android:name="root"
+        android:animation="@anim/progress_indeterminate_rotation_material" />
+
 </animated-vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/progress_small_material.xml b/core/res/res/drawable/progress_small_material.xml
index 43bc569..c6e4380 100644
--- a/core/res/res/drawable/progress_small_material.xml
+++ b/core/res/res/drawable/progress_small_material.xml
@@ -21,4 +21,8 @@
         android:name="progressBar"
         android:animation="@anim/progress_indeterminate_material" />
 
+    <target
+        android:name="root"
+        android:animation="@anim/progress_indeterminate_rotation_material" />
+
 </animated-vector>
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_large.xml b/core/res/res/drawable/vector_drawable_progress_bar_large.xml
index b1900cb..6e0840c 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_large.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_large.xml
@@ -25,8 +25,6 @@
 
     <group
         android:name="root"
-        android:scaleX="1.0"
-        android:scaleY="1.0"
         android:translateX="24.0"
         android:translateY="24.0" >
         <path
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
index 57a6163..7f1231c 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
@@ -25,8 +25,6 @@
 
     <group
         android:name="root"
-        android:scaleX="1.0"
-        android:scaleY="1.0"
         android:translateX="24.0"
         android:translateY="24.0" >
         <path
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_small.xml b/core/res/res/drawable/vector_drawable_progress_bar_small.xml
index ea949b7..58ca101 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_small.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_small.xml
@@ -25,8 +25,6 @@
 
     <group
         android:name="root"
-        android:scaleX="1.0"
-        android:scaleY="1.0"
         android:translateX="24.0"
         android:translateY="24.0" >
         <path
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a3262ed..a71ed47 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -761,6 +761,13 @@
      messages sent to you without showing them to you.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_receiveBluetoothMap">receive Bluetooth messages (MAP)</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_receiveBluetoothMap">Allows the app to receive and process Bluetooth MAP
+      messages. This means the app could monitor or delete messages sent to your
+      device without showing them to you.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_getTasks">retrieve running apps</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_getTasks">Allows the app to retrieve information
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 3857ec0..91f5896 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -141,4 +141,8 @@
     <library name="javax.obex"
             file="/system/framework/javax.obex.jar"/>
 
+    <!-- These are the standard packages that are white-listed to always have internet
+         access while in power save mode, even if they aren't in the foreground. -->
+    <allow-in-power-save package="com.android.providers.downloads" />
+
 </permissions>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index ef0a411..9d7ef45 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -59,14 +59,18 @@
     private final boolean mIsMutable;
 
     /**
-     * Represents whether the Bitmap's content is expected to be pre-multiplied.
+     * Represents whether the Bitmap's content is requested to be pre-multiplied.
      * Note that isPremultiplied() does not directly return this value, because
-     * isPremultiplied() may never return true for a 565 Bitmap.
+     * isPremultiplied() may never return true for a 565 Bitmap or a bitmap
+     * without alpha.
      *
      * setPremultiplied() does directly set the value so that setConfig() and
      * setPremultiplied() aren't order dependent, despite being setters.
+     *
+     * The native bitmap's premultiplication state is kept up to date by
+     * pushing down this preference for every config change.
      */
-    private boolean mIsPremultiplied;
+    private boolean mRequestPremultiplied;
 
     private byte[] mNinePatchChunk;   // may be null
     private int[] mLayoutBounds;   // may be null
@@ -105,7 +109,7 @@
      */
     @SuppressWarnings({"UnusedDeclaration"}) // called from JNI
     Bitmap(long nativeBitmap, byte[] buffer, int width, int height, int density,
-            boolean isMutable, boolean isPremultiplied,
+            boolean isMutable, boolean requestPremultiplied,
             byte[] ninePatchChunk, int[] layoutBounds) {
         if (nativeBitmap == 0) {
             throw new RuntimeException("internal error: native bitmap is 0");
@@ -114,7 +118,7 @@
         mWidth = width;
         mHeight = height;
         mIsMutable = isMutable;
-        mIsPremultiplied = isPremultiplied;
+        mRequestPremultiplied = requestPremultiplied;
         mBuffer = buffer;
         // we delete this in our finalizer
         mNativeBitmap = nativeBitmap;
@@ -132,10 +136,10 @@
      * width/height values
      */
     @SuppressWarnings({"UnusedDeclaration"}) // called from JNI
-    void reinit(int width, int height, boolean isPremultiplied) {
+    void reinit(int width, int height, boolean requestPremultiplied) {
         mWidth = width;
         mHeight = height;
-        mIsPremultiplied = isPremultiplied;
+        mRequestPremultiplied = requestPremultiplied;
     }
 
     /**
@@ -223,7 +227,7 @@
         }
 
         nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length,
-                mIsPremultiplied);
+                mRequestPremultiplied);
         mWidth = width;
         mHeight = height;
     }
@@ -561,7 +565,7 @@
         checkRecycled("Can't copy a recycled bitmap");
         Bitmap b = nativeCopy(mNativeBitmap, config.nativeInt, isMutable);
         if (b != null) {
-            b.setAlphaAndPremultiplied(hasAlpha(), mIsPremultiplied);
+            b.setPremultiplied(mRequestPremultiplied);
             b.mDensity = mDensity;
         }
         return b;
@@ -738,7 +742,8 @@
         // The new bitmap was created from a known bitmap source so assume that
         // they use the same density
         bitmap.mDensity = source.mDensity;
-        bitmap.setAlphaAndPremultiplied(source.hasAlpha(), source.mIsPremultiplied);
+        bitmap.setHasAlpha(source.hasAlpha());
+        bitmap.setPremultiplied(source.mRequestPremultiplied);
 
         canvas.setBitmap(bitmap);
         canvas.drawBitmap(source, srcR, dstR, paint);
@@ -1018,6 +1023,9 @@
      * <p>This method always returns false if {@link #getConfig()} is
      * {@link Bitmap.Config#RGB_565}.</p>
      * 
+     * <p>The return value is undefined if {@link #getConfig()} is
+     * {@link Bitmap.Config#ALPHA_8}.</p>
+     *
      * <p>This method only returns true if {@link #hasAlpha()} returns true.
      * A bitmap with no alpha channel can be used both as a pre-multiplied and
      * as a non pre-multiplied bitmap.</p>
@@ -1033,7 +1041,7 @@
      * @see BitmapFactory.Options#inPremultiplied
      */
     public final boolean isPremultiplied() {
-        return mIsPremultiplied && getConfig() != Config.RGB_565 && hasAlpha();
+        return nativeIsPremultiplied(mNativeBitmap);
     }
 
     /**
@@ -1057,14 +1065,8 @@
      * @see BitmapFactory.Options#inPremultiplied
      */
     public final void setPremultiplied(boolean premultiplied) {
-        mIsPremultiplied = premultiplied;
-        nativeSetAlphaAndPremultiplied(mNativeBitmap, hasAlpha(), premultiplied);
-    }
-
-    /** Helper function to set both alpha and premultiplied. **/
-    private final void setAlphaAndPremultiplied(boolean hasAlpha, boolean premultiplied) {
-        mIsPremultiplied = premultiplied;
-        nativeSetAlphaAndPremultiplied(mNativeBitmap, hasAlpha, premultiplied);
+        mRequestPremultiplied = premultiplied;
+        nativeSetPremultiplied(mNativeBitmap, premultiplied);
     }
 
     /** Returns the bitmap's width */
@@ -1225,7 +1227,7 @@
      * non-opaque per-pixel alpha values.
      */
     public void setHasAlpha(boolean hasAlpha) {
-        nativeSetAlphaAndPremultiplied(mNativeBitmap, hasAlpha, mIsPremultiplied);
+        nativeSetHasAlpha(mNativeBitmap, hasAlpha, mRequestPremultiplied);
     }
 
     /**
@@ -1299,7 +1301,7 @@
     public int getPixel(int x, int y) {
         checkRecycled("Can't call getPixel() on a recycled bitmap");
         checkPixelAccess(x, y);
-        return nativeGetPixel(mNativeBitmap, x, y, mIsPremultiplied);
+        return nativeGetPixel(mNativeBitmap, x, y);
     }
 
     /**
@@ -1333,7 +1335,7 @@
         }
         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
         nativeGetPixels(mNativeBitmap, pixels, offset, stride,
-                        x, y, width, height, mIsPremultiplied);
+                        x, y, width, height);
     }
 
     /**
@@ -1413,7 +1415,7 @@
             throw new IllegalStateException();
         }
         checkPixelAccess(x, y);
-        nativeSetPixel(mNativeBitmap, x, y, color, mIsPremultiplied);
+        nativeSetPixel(mNativeBitmap, x, y, color);
     }
 
     /**
@@ -1450,7 +1452,7 @@
         }
         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
         nativeSetPixels(mNativeBitmap, pixels, offset, stride,
-                        x, y, width, height, mIsPremultiplied);
+                        x, y, width, height);
     }
 
     public static final Parcelable.Creator<Bitmap> CREATOR
@@ -1602,17 +1604,15 @@
     private static native int nativeRowBytes(long nativeBitmap);
     private static native int nativeConfig(long nativeBitmap);
 
-    private static native int nativeGetPixel(long nativeBitmap, int x, int y,
-                                             boolean isPremultiplied);
+    private static native int nativeGetPixel(long nativeBitmap, int x, int y);
     private static native void nativeGetPixels(long nativeBitmap, int[] pixels,
                                                int offset, int stride, int x, int y,
-                                               int width, int height, boolean isPremultiplied);
+                                               int width, int height);
 
-    private static native void nativeSetPixel(long nativeBitmap, int x, int y,
-                                              int color, boolean isPremultiplied);
+    private static native void nativeSetPixel(long nativeBitmap, int x, int y, int color);
     private static native void nativeSetPixels(long nativeBitmap, int[] colors,
                                                int offset, int stride, int x, int y,
-                                               int width, int height, boolean isPremultiplied);
+                                               int width, int height);
     private static native void nativeCopyPixelsToBuffer(long nativeBitmap,
                                                         Buffer dst);
     private static native void nativeCopyPixelsFromBuffer(long nativeBitmap, Buffer src);
@@ -1631,9 +1631,12 @@
 
     private static native void nativePrepareToDraw(long nativeBitmap);
     private static native boolean nativeHasAlpha(long nativeBitmap);
-    private static native void nativeSetAlphaAndPremultiplied(long nativeBitmap,
-                                                              boolean hasAlpha,
-                                                              boolean isPremul);
+    private static native boolean nativeIsPremultiplied(long nativeBitmap);
+    private static native void nativeSetPremultiplied(long nativeBitmap,
+                                                      boolean isPremul);
+    private static native void nativeSetHasAlpha(long nativeBitmap,
+                                                 boolean hasAlpha,
+                                                 boolean requestPremul);
     private static native boolean nativeHasMipMap(long nativeBitmap);
     private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap);
     private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 57c66da..d553d10 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -427,24 +427,46 @@
         return 0;
     }
 
+    /**
+     * @hide
+     * Used to indicate that when parcelling, the tags should be parcelled through the flattened
+     * formatted string, not through the array of strings.
+     * Keep in sync with frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
+     * see definition of kAudioAttributesMarshallTagFlattenTags
+     */
+    public final static int FLATTEN_TAGS = 0x1;
+    /**
+     * When adding tags for writeToParcel(Parcel, int), add them in the list of flags (| NEW_FLAG)
+     */
+    private final static int ALL_PARCEL_FLAGS = FLATTEN_TAGS;
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mUsage);
         dest.writeInt(mContentType);
         dest.writeInt(mFlags);
-        String[] tagsArray = new String[mTags.size()];
-        mTags.toArray(tagsArray);
-        dest.writeStringArray(tagsArray);
+        dest.writeInt(flags & ALL_PARCEL_FLAGS);
+        if ((flags & FLATTEN_TAGS) == 0) {
+            String[] tagsArray = new String[mTags.size()];
+            mTags.toArray(tagsArray);
+            dest.writeStringArray(tagsArray);
+        } else if ((flags & FLATTEN_TAGS) == FLATTEN_TAGS) {
+            dest.writeString(mFormattedTags);
+        }
     }
 
     private AudioAttributes(Parcel in) {
         mUsage = in.readInt();
         mContentType = in.readInt();
         mFlags = in.readInt();
+        boolean hasFlattenedTags = ((in.readInt() & FLATTEN_TAGS) == FLATTEN_TAGS);
         mTags = new HashSet<String>();
-        String[] tagsArray = in.readStringArray();
-        for (int i = tagsArray.length - 1 ; i >= 0 ; i--) {
-            mTags.add(tagsArray[i]);
+        if (hasFlattenedTags) {
+            mTags.add(in.readString());
+        } else {
+            String[] tagsArray = in.readStringArray();
+            for (int i = tagsArray.length - 1 ; i >= 0 ; i--) {
+                mTags.add(tagsArray[i]);
+            }
         }
     }
 
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index d882bc8..628d35b 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -63,6 +63,8 @@
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.provider.Settings.System;
+
+import android.telecomm.TelecommManager;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -2725,17 +2727,13 @@
     }
 
     private boolean isInCommunication() {
-        boolean isOffhook = false;
+        boolean isInAPhoneCall = false;
 
-        if (mVoiceCapable) {
-            try {
-                ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
-                if (phone != null) isOffhook = phone.isOffhook();
-            } catch (RemoteException e) {
-                Log.w(TAG, "Couldn't connect to phone service", e);
-            }
-        }
-        return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION);
+        TelecommManager telecommManager =
+                (TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE);
+        isInAPhoneCall = telecommManager.isInAPhoneCall();
+
+        return (isInAPhoneCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
     }
 
     /**
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index d1909bc..490a8fd 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1441,6 +1441,36 @@
 
     private native void _setAudioStreamType(int streamtype);
 
+    // Keep KEY_PARAMETER_* in sync with include/media/mediaplayer.h
+    private final static int KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400;
+    /**
+     * Sets the parameter indicated by key.
+     * @param key key indicates the parameter to be set.
+     * @param value value of the parameter to be set.
+     * @return true if the parameter is set successfully, false otherwise
+     * {@hide}
+     */
+    private native boolean setParameter(int key, Parcel value);
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Must call this method before prepare() or
+     * prepareAsync() in order for the audio attributes to become effective
+     * thereafter.
+     * @param attributes a non-null set of audio attributes
+     */
+    public void setAudioAttributes(AudioAttributes attributes) throws IllegalArgumentException {
+        if (attributes == null) {
+            final String msg = "Cannot set audio attributes to null";
+            throw new IllegalArgumentException(msg);
+        }
+        Parcel pattributes = Parcel.obtain();
+        attributes.writeToParcel(pattributes, AudioAttributes.FLATTEN_TAGS);
+        setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, pattributes);
+        pattributes.recycle();
+    }
+
     /**
      * Sets the player to be looping or non-looping.
      *
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 9516bf8..1255276 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1185,6 +1185,7 @@
         HashSet<String> existingFiles = new HashSet<String>();
         String directory = "/sdcard/DCIM/.thumbnails";
         String [] files = (new File(directory)).list();
+        Cursor c = null;
         if (files == null)
             files = new String[0];
 
@@ -1194,7 +1195,7 @@
         }
 
         try {
-            Cursor c = mMediaProvider.query(
+            c = mMediaProvider.query(
                     mPackageName,
                     mThumbsUri,
                     new String [] { "_data" },
@@ -1219,11 +1220,12 @@
             }
 
             Log.v(TAG, "/pruneDeadThumbnailFiles... " + c);
+        } catch (RemoteException e) {
+            // We will soon be killed...
+        } finally {
             if (c != null) {
                 c.close();
             }
-        } catch (RemoteException e) {
-            // We will soon be killed...
         }
     }
 
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 6f42057..4587cf56 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -514,6 +514,25 @@
     return (jint) streamtype;
 }
 
+static jboolean
+android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request)
+{
+    ALOGV("setParameter: key %d", key);
+    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+    if (mp == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return false;
+    }
+
+    Parcel *request = parcelForJavaObject(env, java_request);
+    status_t err = mp->setParameter(key, *request);
+    if (err == OK) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
 static void
 android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping)
 {
@@ -857,6 +876,7 @@
     {"_reset",              "()V",                              (void *)android_media_MediaPlayer_reset},
     {"_setAudioStreamType", "(I)V",                             (void *)android_media_MediaPlayer_setAudioStreamType},
     {"_getAudioStreamType", "()I",                              (void *)android_media_MediaPlayer_getAudioStreamType},
+    {"setParameter",        "(ILandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_setParameter},
     {"setLooping",          "(Z)V",                             (void *)android_media_MediaPlayer_setLooping},
     {"isLooping",           "()Z",                              (void *)android_media_MediaPlayer_isLooping},
     {"_setVolume",          "(FF)V",                            (void *)android_media_MediaPlayer_setVolume},
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
index 0c65283..75278b5 100644
--- a/obex/javax/obex/ClientOperation.java
+++ b/obex/javax/obex/ClientOperation.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2014 The Android Open Source Project
  * Copyright (c) 2008-2009, Motorola, Inc.
  *
  * All rights reserved.
@@ -66,6 +67,8 @@
 
     private boolean mGetOperation;
 
+    private boolean mGetFinalFlag;
+
     private HeaderSet mRequestHeader;
 
     private HeaderSet mReplyHeader;
@@ -90,6 +93,7 @@
         mOperationDone = false;
         mMaxPacketSize = maxSize;
         mGetOperation = type;
+        mGetFinalFlag = false;
 
         mPrivateInputOpen = false;
         mPrivateOutputOpen = false;
@@ -131,6 +135,15 @@
     }
 
     /**
+     * Allows to set flag which will force GET to be always sent as single packet request with
+     * final flag set. This is to improve compatibility with some profiles, i.e. PBAP which
+     * require requests to be sent this way.
+     */
+    public void setGetFinalFlag(boolean flag) {
+        mGetFinalFlag = flag;
+    }
+
+    /**
      * Sends an ABORT message to the server. By calling this method, the
      * corresponding input and output streams will be closed along with this
      * object.
@@ -551,15 +564,25 @@
 
         if (mGetOperation) {
             if (!mOperationDone) {
-                mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
-                while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
-                    more = sendRequest(0x03);
-                }
+                if (!mGetFinalFlag) {
+                    mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+                    while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+                        more = sendRequest(0x03);
+                    }
 
-                if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
-                    mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
-                }
-                if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+                    if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+                        mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
+                    }
+                    if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+                        mOperationDone = true;
+                    }
+                } else {
+                    more = sendRequest(0x83);
+
+                    if (more) {
+                        throw new IOException("FINAL_GET forced but data did not fit into single packet!");
+                    }
+
                     mOperationDone = true;
                 }
             }
@@ -613,7 +636,16 @@
                 if (mPrivateInput == null) {
                     mPrivateInput = new PrivateInputStream(this);
                 }
-                sendRequest(0x03);
+
+                if (!mGetFinalFlag) {
+                    sendRequest(0x03);
+                } else {
+                    sendRequest(0x83);
+
+                    if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+                        mOperationDone = true;
+                    }
+                }
                 return true;
 
             } else if (mOperationDone) {
diff --git a/obex/javax/obex/HeaderSet.java b/obex/javax/obex/HeaderSet.java
index 2b3066f..51b560a 100644
--- a/obex/javax/obex/HeaderSet.java
+++ b/obex/javax/obex/HeaderSet.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2014 The Android Open Source Project
  * Copyright (c) 2008-2009, Motorola, Inc.
  *
  * All rights reserved.
@@ -181,6 +182,8 @@
 
     private String mName; // null terminated Unicode text string
 
+    private boolean mEmptyName;
+
     private String mType; // null terminated ASCII text string
 
     private Long mLength; // 4 byte unsigend integer
@@ -235,6 +238,25 @@
     }
 
     /**
+     * Sets flag for special "value" of NAME header which should be empty. This
+     * is not the same as NAME header with empty string in which case it will
+     * have length of 5 bytes. It should be 3 bytes with only header id and
+     * length field.
+     */
+    public void setEmptyNameHeader() {
+        mName = null;
+        mEmptyName = true;
+    }
+
+    /**
+     * Gets flag for special "value" of NAME header which should be empty. See
+     * above.
+     */
+    public boolean getEmptyNameHeader() {
+        return mEmptyName;
+    }
+
+    /**
      * Sets the value of the header identifier to the value provided. The type
      * of object must correspond to the Java type defined in the description of
      * this interface. If <code>null</code> is passed as the
@@ -269,6 +291,7 @@
                 if ((headerValue != null) && (!(headerValue instanceof String))) {
                     throw new IllegalArgumentException("Name must be a String");
                 }
+                mEmptyName = false;
                 mName = (String)headerValue;
                 break;
             case TYPE:
diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java
index 8c12a20..0a06709 100644
--- a/obex/javax/obex/ObexHelper.java
+++ b/obex/javax/obex/ObexHelper.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2014 The Android Open Source Project
  * Copyright (c) 2008-2009, Motorola, Inc.
  *
  * All rights reserved.
@@ -387,6 +388,11 @@
                 if (nullOut) {
                     headImpl.setHeader(HeaderSet.NAME, null);
                 }
+            } else if (headImpl.getEmptyNameHeader()) {
+                out.write((byte) HeaderSet.NAME);
+                lengthArray[0] = (byte) 0x00;
+                lengthArray[1] = (byte) 0x03;
+                out.write(lengthArray);
             }
 
             // Type Header
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 0720704..d152887 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -50,6 +50,7 @@
     private int mPanelPaddingBottom;
     private int mDualTileUnderlap;
     private boolean mExpanded;
+    private boolean mListening;
 
     private TileRecord mDetailRecord;
     private Callback mCallback;
@@ -100,9 +101,14 @@
         if (!mExpanded) {
             showDetail(false /*show*/, mDetailRecord);
         }
+    }
+
+    public void setListening(boolean listening) {
+        if (mListening == listening) return;
+        mListening = listening;
         for (TileRecord r : mRecords) {
-            r.tile.setListening(mExpanded);
-            if (mExpanded) {
+            r.tile.setListening(mListening);
+            if (mListening) {
                 r.tile.refreshState();
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index c82bdf6..fd2db8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -35,6 +35,7 @@
 import android.widget.TextView;
 
 import com.android.systemui.R;
+import com.android.systemui.qs.QSPanel;
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.GestureRecorder;
@@ -61,7 +62,7 @@
     private KeyguardPageSwipeHelper mPageSwiper;
     private StatusBarHeaderView mHeader;
     private View mQsContainer;
-    private View mQsPanel;
+    private QSPanel mQsPanel;
     private View mKeyguardStatusView;
     private ObservableScrollView mScrollView;
     private TextView mClockView;
@@ -136,7 +137,7 @@
         mHeader.setOverlayParent(this);
         mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
         mQsContainer = findViewById(R.id.quick_settings_container);
-        mQsPanel = findViewById(R.id.quick_settings_panel);
+        mQsPanel = (QSPanel) findViewById(R.id.quick_settings_panel);
         mClockView = (TextView) findViewById(R.id.clock_view);
         mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
         mScrollView.setListener(this);
@@ -873,6 +874,20 @@
         super.onExpandingFinished();
         mNotificationStackScroller.onExpansionStopped();
         mIsExpanding = false;
+        if (mExpandedHeight == 0f) {
+            mHeader.setListening(false);
+            mQsPanel.setListening(false);
+        } else {
+            mHeader.setListening(true);
+            mQsPanel.setListening(true);
+        }
+    }
+
+    @Override
+    public void instantExpand() {
+        super.instantExpand();
+        mHeader.setListening(true);
+        mQsPanel.setListening(true);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index f70010e..03c23e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -31,7 +31,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.app.ActivityManager;
@@ -518,7 +517,7 @@
         Resources res = context.getResources();
 
         updateDisplaySize(); // populates mDisplayMetrics
-        loadDimens();
+        updateResources();
 
         mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 9e9de5d..3e2dcef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -45,6 +45,7 @@
     private static final float EXPANSION_RUBBERBAND_FACTOR = 0.35f;
 
     private boolean mExpanded;
+    private boolean mListening;
     private boolean mOverscrolled;
     private boolean mKeyguardShowing;
 
@@ -145,6 +146,14 @@
         return mExpandedHeight;
     }
 
+    public void setListening(boolean listening) {
+        if (listening == mListening) {
+            return;
+        }
+        mListening = listening;
+        updateBrightnessControllerState();
+    }
+
     public void setExpanded(boolean expanded, boolean overscrolled) {
         boolean changed = expanded != mExpanded;
         boolean overscrollChanged = overscrolled != mOverscrolled;
@@ -154,7 +163,6 @@
             updateHeights();
             updateVisibilities();
             updateSystemIconsLayoutParams();
-            updateBrightnessControllerState();
             updateZTranslation();
             updateClickTargets();
             updateWidth();
@@ -254,7 +262,7 @@
     }
 
     private void updateBrightnessControllerState() {
-        if (mExpanded) {
+        if (mListening) {
             mBrightnessController.registerCallbacks();
         } else {
             mBrightnessController.unregisterCallbacks();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ddfa9c1..95edf07 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -64,7 +64,7 @@
 import android.provider.Settings;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
-import android.telephony.TelephonyManager;
+import android.telecomm.TelecommManager;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
@@ -2038,8 +2038,8 @@
                 ServiceManager.checkService(DreamService.DREAM_SERVICE));
     }
 
-    TelephonyManager getTelephonyService() {
-        return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+    TelecommManager getTelecommService() {
+        return (TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE);
     }
 
     static IAudioService getAudioService() {
@@ -2126,10 +2126,10 @@
                 }
 
                 // If an incoming call is ringing, HOME is totally disabled.
-                // (The user is already on the InCallScreen at this point,
+                // (The user is already on the InCallUI at this point,
                 // and his ONLY options are to answer or reject the call.)
-                TelephonyManager telephonyManager = getTelephonyService();
-                if (telephonyManager != null && telephonyManager.isRinging()) {
+                TelecommManager telecommManager = getTelecommService();
+                if (telecommManager != null && telecommManager.isRinging()) {
                     Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
                     return -1;
                 }
@@ -4152,9 +4152,9 @@
                     }
                 }
                 if (down) {
-                    TelephonyManager telephonyManager = getTelephonyService();
-                    if (telephonyManager != null) {
-                        if (telephonyManager.isRinging()) {
+                    TelecommManager telecommManager = getTelecommService();
+                    if (telecommManager != null) {
+                        if (telecommManager.isRinging()) {
                             // If an incoming call is ringing, either VOLUME key means
                             // "silence ringer".  We handle these keys here, rather than
                             // in the InCallScreen, to make sure we'll respond to them
@@ -4166,14 +4166,14 @@
 
                             // Silence the ringer.  (It's safe to call this
                             // even if the ringer has already been silenced.)
-                            telephonyManager.silenceRinger();
+                            telecommManager.silenceRinger();
 
                             // And *don't* pass this key thru to the current activity
                             // (which is probably the InCallScreen.)
                             result &= ~ACTION_PASS_TO_USER;
                             break;
                         }
-                        if (telephonyManager.isOffhook()
+                        if (telecommManager.isInAPhoneCall()
                                 && (result & ACTION_PASS_TO_USER) == 0) {
                             // If we are in call but we decided not to pass the key to
                             // the application, just pass it to the session service.
@@ -4199,10 +4199,10 @@
             case KeyEvent.KEYCODE_ENDCALL: {
                 result &= ~ACTION_PASS_TO_USER;
                 if (down) {
-                    TelephonyManager telephonyManager = getTelephonyService();
+                    TelecommManager telecommManager = getTelecommService();
                     boolean hungUp = false;
-                    if (telephonyManager != null) {
-                        hungUp = telephonyManager.endCall();
+                    if (telecommManager != null) {
+                        hungUp = telecommManager.endCall();
                     }
                     interceptPowerKeyDown(!interactive || hungUp);
                 } else {
@@ -4238,19 +4238,19 @@
                         interceptScreenshotChord();
                     }
 
-                    TelephonyManager telephonyManager = getTelephonyService();
+                    TelecommManager telecommManager = getTelecommService();
                     boolean hungUp = false;
-                    if (telephonyManager != null) {
-                        if (telephonyManager.isRinging()) {
+                    if (telecommManager != null) {
+                        if (telecommManager.isRinging()) {
                             // Pressing Power while there's a ringing incoming
                             // call should silence the ringer.
-                            telephonyManager.silenceRinger();
+                            telecommManager.silenceRinger();
                         } else if ((mIncallPowerBehavior
                                 & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
-                                && telephonyManager.isOffhook() && interactive) {
+                                && telecommManager.isInAPhoneCall() && interactive) {
                             // Otherwise, if "Power button ends call" is enabled,
                             // the Power button will hang up any current active call.
-                            hungUp = telephonyManager.endCall();
+                            hungUp = telecommManager.endCall();
                         }
                     }
                     interceptPowerKeyDown(!interactive || hungUp
@@ -4286,9 +4286,9 @@
             case KeyEvent.KEYCODE_MEDIA_PAUSE:
             case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
                 if (down) {
-                    TelephonyManager telephonyManager = getTelephonyService();
-                    if (telephonyManager != null) {
-                        if (!telephonyManager.isIdle()) {
+                    TelecommManager telecommManager = getTelecommService();
+                    if (telecommManager != null) {
+                        if (telecommManager.isInAPhoneCall()) {
                             // Suppress PLAY/PAUSE toggle when phone is ringing or in-call
                             // to avoid music playback.
                             break;
@@ -4321,12 +4321,12 @@
 
             case KeyEvent.KEYCODE_CALL: {
                 if (down) {
-                    TelephonyManager telephonyManager = getTelephonyService();
-                    if (telephonyManager != null) {
-                        if (telephonyManager.isRinging()) {
+                    TelecommManager telecommManager = getTelecommService();
+                    if (telecommManager != null) {
+                        if (telecommManager.isRinging()) {
                             Log.i(TAG, "interceptKeyBeforeQueueing:"
                                   + " CALL key-down while ringing: Answer the call!");
-                            telephonyManager.answerRingingCall();
+                            telecommManager.acceptRingingCall();
 
                             // And *don't* pass this key thru to the current activity
                             // (which is presumably the InCallScreen.)
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
new file mode 100644
index 0000000..fdcb3b9
--- /dev/null
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2014 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;
+
+import android.content.pm.FeatureInfo;
+import android.os.*;
+import android.os.Process;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.Xml;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import static com.android.internal.util.ArrayUtils.appendInt;
+
+/**
+ * Loads global system configuration info.
+ */
+public class SystemConfig {
+    static final String TAG = "SystemConfig";
+
+    static SystemConfig sInstance;
+
+    // Group-ids that are given to all packages as read from etc/permissions/*.xml.
+    int[] mGlobalGids;
+
+    // These are the built-in uid -> permission mappings that were read from the
+    // system configuration files.
+    final SparseArray<HashSet<String>> mSystemPermissions =
+            new SparseArray<HashSet<String>>();
+
+    // These are the built-in shared libraries that were read from the
+    // system configuration files.  Keys are the library names; strings are the
+    // paths to the libraries.
+    final ArrayMap<String, String> mSharedLibraries
+            = new ArrayMap<String, String>();
+
+    // These are the features this devices supports that were read from the
+    // system configuration files.
+    final HashMap<String, FeatureInfo> mAvailableFeatures =
+            new HashMap<String, FeatureInfo>();
+
+    public static final class PermissionEntry {
+        public final String name;
+        public int[] gids;
+
+        PermissionEntry(String _name) {
+            name = _name;
+        }
+    }
+
+    // These are the permission -> gid mappings that were read from the
+    // system configuration files.
+    final ArrayMap<String, PermissionEntry> mPermissions =
+            new ArrayMap<String, PermissionEntry>();
+
+    // These are the packages that are white-listed to be able to run in the
+    // background while in power save mode, as read from the configuration files.
+    final ArraySet<String> mAllowInPowerSave = new ArraySet<String>();
+
+    public static SystemConfig getInstance() {
+        synchronized (SystemConfig.class) {
+            if (sInstance == null) {
+                sInstance = new SystemConfig();
+            }
+            return sInstance;
+        }
+    }
+
+    public int[] getGlobalGids() {
+        return mGlobalGids;
+    }
+
+    public SparseArray<HashSet<String>> getSystemPermissions() {
+        return mSystemPermissions;
+    }
+
+    public ArrayMap<String, String> getSharedLibraries() {
+        return mSharedLibraries;
+    }
+
+    public HashMap<String, FeatureInfo> getAvailableFeatures() {
+        return mAvailableFeatures;
+    }
+
+    public ArrayMap<String, PermissionEntry> getPermissions() {
+        return mPermissions;
+    }
+
+    public ArraySet<String> getAllowInPowerSave() {
+        return mAllowInPowerSave;
+    }
+
+    SystemConfig() {
+        // Read configuration from system
+        readPermissions(Environment.buildPath(
+                Environment.getRootDirectory(), "etc", "sysconfig"), false);
+        // Read configuration from the old permissions dir
+        readPermissions(Environment.buildPath(
+                Environment.getRootDirectory(), "etc", "permissions"), false);
+        // Only read features from OEM config
+        readPermissions(Environment.buildPath(
+                Environment.getOemDirectory(), "etc", "sysconfig"), true);
+        readPermissions(Environment.buildPath(
+                Environment.getOemDirectory(), "etc", "permissions"), true);
+    }
+
+    void readPermissions(File libraryDir, boolean onlyFeatures) {
+        // Read permissions from given directory.
+        if (!libraryDir.exists() || !libraryDir.isDirectory()) {
+            if (!onlyFeatures) {
+                Slog.w(TAG, "No directory " + libraryDir + ", skipping");
+            }
+            return;
+        }
+        if (!libraryDir.canRead()) {
+            Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
+            return;
+        }
+
+        // Iterate over the files in the directory and scan .xml files
+        for (File f : libraryDir.listFiles()) {
+            // We'll read platform.xml last
+            if (f.getPath().endsWith("etc/permissions/platform.xml")) {
+                continue;
+            }
+
+            if (!f.getPath().endsWith(".xml")) {
+                Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
+                continue;
+            }
+            if (!f.canRead()) {
+                Slog.w(TAG, "Permissions library file " + f + " cannot be read");
+                continue;
+            }
+
+            readPermissionsFromXml(f, onlyFeatures);
+        }
+
+        // Read permissions from .../etc/permissions/platform.xml last so it will take precedence
+        final File permFile = new File(Environment.getRootDirectory(),
+                "etc/permissions/platform.xml");
+        readPermissionsFromXml(permFile, onlyFeatures);
+    }
+
+    private void readPermissionsFromXml(File permFile, boolean onlyFeatures) {
+        FileReader permReader = null;
+        try {
+            permReader = new FileReader(permFile);
+        } catch (FileNotFoundException e) {
+            Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
+            return;
+        }
+
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(permReader);
+
+            int type;
+            while ((type=parser.next()) != parser.START_TAG
+                       && type != parser.END_DOCUMENT) {
+                ;
+            }
+
+            if (type != parser.START_TAG) {
+                throw new XmlPullParserException("No start tag found");
+            }
+
+            if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
+                throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
+                        ", expected 'permissions' or 'config'");
+            }
+
+            while (true) {
+                XmlUtils.nextElement(parser);
+                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+                    break;
+                }
+
+                String name = parser.getName();
+                if ("group".equals(name) && !onlyFeatures) {
+                    String gidStr = parser.getAttributeValue(null, "gid");
+                    if (gidStr != null) {
+                        int gid = android.os.Process.getGidForName(gidStr);
+                        mGlobalGids = appendInt(mGlobalGids, gid);
+                    } else {
+                        Slog.w(TAG, "<group> without gid at "
+                                + parser.getPositionDescription());
+                    }
+
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                } else if ("permission".equals(name) && !onlyFeatures) {
+                    String perm = parser.getAttributeValue(null, "name");
+                    if (perm == null) {
+                        Slog.w(TAG, "<permission> without name at "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    perm = perm.intern();
+                    readPermission(parser, perm);
+
+                } else if ("assign-permission".equals(name) && !onlyFeatures) {
+                    String perm = parser.getAttributeValue(null, "name");
+                    if (perm == null) {
+                        Slog.w(TAG, "<assign-permission> without name at "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    String uidStr = parser.getAttributeValue(null, "uid");
+                    if (uidStr == null) {
+                        Slog.w(TAG, "<assign-permission> without uid at "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    int uid = Process.getUidForName(uidStr);
+                    if (uid < 0) {
+                        Slog.w(TAG, "<assign-permission> with unknown uid \""
+                                + uidStr + "\" at "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    perm = perm.intern();
+                    HashSet<String> perms = mSystemPermissions.get(uid);
+                    if (perms == null) {
+                        perms = new HashSet<String>();
+                        mSystemPermissions.put(uid, perms);
+                    }
+                    perms.add(perm);
+                    XmlUtils.skipCurrentTag(parser);
+
+                } else if ("library".equals(name) && !onlyFeatures) {
+                    String lname = parser.getAttributeValue(null, "name");
+                    String lfile = parser.getAttributeValue(null, "file");
+                    if (lname == null) {
+                        Slog.w(TAG, "<library> without name at "
+                                + parser.getPositionDescription());
+                    } else if (lfile == null) {
+                        Slog.w(TAG, "<library> without file at "
+                                + parser.getPositionDescription());
+                    } else {
+                        //Log.i(TAG, "Got library " + lname + " in " + lfile);
+                        mSharedLibraries.put(lname, lfile);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
+                } else if ("feature".equals(name)) {
+                    String fname = parser.getAttributeValue(null, "name");
+                    if (fname == null) {
+                        Slog.w(TAG, "<feature> without name at "
+                                + parser.getPositionDescription());
+                    } else {
+                        //Log.i(TAG, "Got feature " + fname);
+                        FeatureInfo fi = new FeatureInfo();
+                        fi.name = fname;
+                        mAvailableFeatures.put(fname, fi);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
+                } else if ("allow-in-power-save".equals(name)) {
+                    String pkgname = parser.getAttributeValue(null, "package");
+                    if (pkgname == null) {
+                        Slog.w(TAG, "<allow-in-power-save> without package at "
+                                + parser.getPositionDescription());
+                    } else {
+                        mAllowInPowerSave.add(pkgname);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
+                } else {
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                }
+
+            }
+            permReader.close();
+        } catch (XmlPullParserException e) {
+            Slog.w(TAG, "Got execption parsing permissions.", e);
+        } catch (IOException e) {
+            Slog.w(TAG, "Got execption parsing permissions.", e);
+        }
+    }
+
+    void readPermission(XmlPullParser parser, String name)
+            throws IOException, XmlPullParserException {
+
+        name = name.intern();
+
+        PermissionEntry perm = mPermissions.get(name);
+        if (perm == null) {
+            perm = new PermissionEntry(name);
+            mPermissions.put(name, perm);
+        }
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+               && (type != XmlPullParser.END_TAG
+                       || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG
+                    || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if ("group".equals(tagName)) {
+                String gidStr = parser.getAttributeValue(null, "gid");
+                if (gidStr != null) {
+                    int gid = Process.getGidForName(gidStr);
+                    perm.gids = appendInt(perm.gids, gid);
+                } else {
+                    Slog.w(TAG, "<group> without gid at "
+                            + parser.getPositionDescription());
+                }
+            }
+            XmlUtils.skipCurrentTag(parser);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 933046b..17268c3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -36,9 +36,6 @@
 import android.app.IAppTask;
 import android.app.admin.DevicePolicyManager;
 import android.appwidget.AppWidgetManager;
-import android.content.DialogInterface.OnClickListener;
-import android.content.res.Resources;
-import android.graphics.BitmapFactory;
 import android.graphics.Rect;
 import android.os.BatteryStats;
 import android.os.PersistableBundle;
@@ -174,12 +171,8 @@
 import android.os.UpdateLock;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.text.Spannable;
-import android.text.SpannableString;
 import android.text.format.DateUtils;
 import android.text.format.Time;
-import android.text.style.DynamicDrawableSpan;
-import android.text.style.ImageSpan;
 import android.util.AtomicFile;
 import android.util.EventLog;
 import android.util.Log;
@@ -193,7 +186,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
-import android.widget.TextView;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 3cbc6e2..5c5e3e3 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -365,6 +365,20 @@
         }
     }
 
+    public void noteFlashlightOn() {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteFlashlightOnLocked();
+        }
+    }
+
+    public void noteFlashlightOff() {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteFlashlightOffLocked();
+        }
+    }
+
     public void noteWifiRunning(WorkSource ws) {
         enforceCallingPermission();
         synchronized (mStats) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 416a6b1..142094f 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -39,6 +39,7 @@
 import static android.net.NetworkPolicy.WARNING_DISABLED;
 import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
+import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
@@ -111,6 +112,7 @@
 import android.os.IPowerManager;
 import android.os.Message;
 import android.os.MessageQueue.IdleHandler;
+import android.os.PowerManagerInternal;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -119,6 +121,8 @@
 import android.telephony.TelephonyManager;
 import android.text.format.Formatter;
 import android.text.format.Time;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.Log;
 import android.util.NtpTrustedTime;
@@ -133,6 +137,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.LocalServices;
+import com.android.server.SystemConfig;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 import com.google.android.collect.Sets;
@@ -153,7 +159,6 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
 
 import libcore.io.IoUtils;
@@ -240,35 +245,43 @@
 
     private IConnectivityManager mConnManager;
     private INotificationManager mNotifManager;
+    private PowerManagerInternal mPowerManagerInternal;
 
     private final Object mRulesLock = new Object();
 
     private volatile boolean mScreenOn;
     private volatile boolean mRestrictBackground;
+    private volatile boolean mRestrictPower;
 
     private final boolean mSuppressDefaultPolicy;
 
     /** Defined network policies. */
-    private HashMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = Maps.newHashMap();
+    private final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<
+            NetworkTemplate, NetworkPolicy>();
     /** Currently active network rules for ifaces. */
-    private HashMap<NetworkPolicy, String[]> mNetworkRules = Maps.newHashMap();
+    private final ArrayMap<NetworkPolicy, String[]> mNetworkRules = new ArrayMap<
+            NetworkPolicy, String[]>();
 
     /** Defined UID policies. */
-    private SparseIntArray mUidPolicy = new SparseIntArray();
+    private final SparseIntArray mUidPolicy = new SparseIntArray();
     /** Currently derived rules for each UID. */
-    private SparseIntArray mUidRules = new SparseIntArray();
+    private final SparseIntArray mUidRules = new SparseIntArray();
+
+    /** UIDs that have been white-listed to always be able to have network access in
+     * power save mode. */
+    private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray();
 
     /** Set of ifaces that are metered. */
     private HashSet<String> mMeteredIfaces = Sets.newHashSet();
     /** Set of over-limit templates that have been notified. */
-    private HashSet<NetworkTemplate> mOverLimitNotified = Sets.newHashSet();
+    private final HashSet<NetworkTemplate> mOverLimitNotified = Sets.newHashSet();
 
     /** Set of currently active {@link Notification} tags. */
-    private HashSet<String> mActiveNotifs = Sets.newHashSet();
+    private final HashSet<String> mActiveNotifs = Sets.newHashSet();
 
     /** Foreground at both UID and PID granularity. */
-    private SparseBooleanArray mUidForeground = new SparseBooleanArray();
-    private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
+    private final SparseBooleanArray mUidForeground = new SparseBooleanArray();
+    private final SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
             SparseBooleanArray>();
 
     private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<
@@ -328,12 +341,42 @@
             return;
         }
 
+        final PackageManager pm = mContext.getPackageManager();
+
         synchronized (mRulesLock) {
+            SystemConfig sysConfig = SystemConfig.getInstance();
+            ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
+            for (int i=0; i<allowPower.size(); i++) {
+                String pkg = allowPower.valueAt(i);
+                try {
+                    ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
+                    if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+                        mPowerSaveWhitelistAppIds.put(UserHandle.getAppId(ai.uid), true);
+                    }
+                } catch (PackageManager.NameNotFoundException e) {
+                }
+            }
+
+            mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
+            mPowerManagerInternal.registerLowPowerModeObserver(
+                    new PowerManagerInternal.LowPowerModeListener() {
+                @Override
+                public void onLowPowerModeChanged(boolean enabled) {
+                    synchronized (mRulesLock) {
+                        if (mRestrictPower != enabled) {
+                            mRestrictPower = enabled;
+                            updateRulesForGlobalChangeLocked(true);
+                        }
+                    }
+                }
+            });
+            mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
+
             // read policy from disk
             readPolicyLocked();
 
-            if (mRestrictBackground) {
-                updateRulesForRestrictBackgroundLocked();
+            if (mRestrictBackground || mRestrictPower) {
+                updateRulesForGlobalChangeLocked(true);
                 updateNotificationsLocked();
             }
         }
@@ -482,7 +525,7 @@
 
             // Update global restrict for new user
             synchronized (mRulesLock) {
-                updateRulesForRestrictBackgroundLocked();
+                updateRulesForGlobalChangeLocked(true);
             }
         }
     };
@@ -633,7 +676,8 @@
 
         // examine stats for each active policy
         final long currentTime = currentTimeMillis();
-        for (NetworkPolicy policy : mNetworkPolicy.values()) {
+        for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+            final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
             // ignore policies that aren't relevant to user
             if (!isTemplateRelevant(policy.template)) continue;
             if (!policy.hasCycle()) continue;
@@ -912,7 +956,8 @@
         // completely, which is currently rare case.
 
         final long currentTime = currentTimeMillis();
-        for (NetworkPolicy policy : mNetworkPolicy.values()) {
+        for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+            final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
             // shortcut when policy has no limit
             if (policy.limitBytes == LIMIT_DISABLED || !policy.hasCycle()) {
                 setNetworkTemplateEnabled(policy.template, true);
@@ -978,29 +1023,41 @@
             return;
         }
 
+        // If we are in restrict power mode, we want to treat all interfaces
+        // as metered, to restrict access to the network by uid.  However, we
+        // will not have a bandwidth limit.  Also only do this if restrict
+        // background data use is *not* enabled, since that takes precendence
+        // use over those networks can have a cost associated with it).
+        final boolean powerSave = mRestrictPower && !mRestrictBackground;
+
         // first, derive identity for all connected networks, which can be used
         // to match against templates.
-        final HashMap<NetworkIdentity, String> networks = Maps.newHashMap();
+        final ArrayMap<NetworkIdentity, String> networks = new ArrayMap();
+        final ArraySet<String> connIfaces = new ArraySet<String>();
         for (NetworkState state : states) {
             // stash identity and iface away for later use
             if (state.networkInfo.isConnected()) {
                 final String iface = state.linkProperties.getInterfaceName();
                 final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
                 networks.put(ident, iface);
+                if (powerSave) {
+                    connIfaces.add(iface);
+                }
             }
         }
 
         // build list of rules and ifaces to enforce them against
         mNetworkRules.clear();
         final ArrayList<String> ifaceList = Lists.newArrayList();
-        for (NetworkPolicy policy : mNetworkPolicy.values()) {
+        for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+            final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
 
             // collect all active ifaces that match this template
             ifaceList.clear();
-            for (Map.Entry<NetworkIdentity, String> entry : networks.entrySet()) {
-                final NetworkIdentity ident = entry.getKey();
+            for (int j = networks.size()-1; j >= 0; j--) {
+                final NetworkIdentity ident = networks.keyAt(j);
                 if (policy.template.matches(ident)) {
-                    final String iface = entry.getValue();
+                    final String iface = networks.valueAt(j);
                     ifaceList.add(iface);
                 }
             }
@@ -1017,8 +1074,9 @@
         // apply each policy that we found ifaces for; compute remaining data
         // based on current cycle and historical stats, and push to kernel.
         final long currentTime = currentTimeMillis();
-        for (NetworkPolicy policy : mNetworkRules.keySet()) {
-            final String[] ifaces = mNetworkRules.get(policy);
+        for (int i = mNetworkRules.size()-1; i >= 0; i--) {
+            final NetworkPolicy policy = mNetworkRules.keyAt(i);
+            final String[] ifaces = mNetworkRules.valueAt(i);
 
             final long start;
             final long totalBytes;
@@ -1063,6 +1121,9 @@
                     removeInterfaceQuota(iface);
                     setInterfaceQuota(iface, quotaBytes);
                     newMeteredIfaces.add(iface);
+                    if (powerSave) {
+                        connIfaces.remove(iface);
+                    }
                 }
             }
 
@@ -1075,6 +1136,13 @@
             }
         }
 
+        for (int i = connIfaces.size()-1; i >= 0; i--) {
+            String iface = connIfaces.valueAt(i);
+            removeInterfaceQuota(iface);
+            setInterfaceQuota(iface, Long.MAX_VALUE);
+            newMeteredIfaces.add(iface);
+        }
+
         mHandler.obtainMessage(MSG_ADVISE_PERSIST_THRESHOLD, lowestRule).sendToTarget();
 
         // remove quota on any trailing interfaces
@@ -1108,9 +1176,10 @@
 
         // examine to see if any policy is defined for active mobile
         boolean mobileDefined = false;
-        for (NetworkPolicy policy : mNetworkPolicy.values()) {
-            if (policy.template.matches(probeIdent)) {
+        for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+            if (mNetworkPolicy.valueAt(i).template.matches(probeIdent)) {
                 mobileDefined = true;
+                break;
             }
         }
 
@@ -1226,7 +1295,7 @@
                         final int policy = readIntAttribute(in, ATTR_POLICY);
 
                         if (UserHandle.isApp(uid)) {
-                            setUidPolicyUnchecked(uid, policy, false);
+                            setUidPolicyUncheckedLocked(uid, policy, false);
                         } else {
                             Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
                         }
@@ -1237,7 +1306,7 @@
                         // TODO: set for other users during upgrade
                         final int uid = UserHandle.getUid(UserHandle.USER_OWNER, appId);
                         if (UserHandle.isApp(uid)) {
-                            setUidPolicyUnchecked(uid, policy, false);
+                            setUidPolicyUncheckedLocked(uid, policy, false);
                         } else {
                             Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
                         }
@@ -1289,7 +1358,8 @@
             writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground);
 
             // write all known network policies
-            for (NetworkPolicy policy : mNetworkPolicy.values()) {
+            for (int i = 0; i < mNetworkPolicy.size(); i++) {
+                final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
                 final NetworkTemplate template = policy.template;
 
                 out.startTag(null, TAG_NETWORK_POLICY);
@@ -1346,24 +1416,59 @@
             throw new IllegalArgumentException("cannot apply policy to UID " + uid);
         }
 
-        setUidPolicyUnchecked(uid, policy, true);
+        synchronized (mRulesLock) {
+            final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
+            if (oldPolicy != policy) {
+                setUidPolicyUncheckedLocked(uid, policy, true);
+            }
+        }
     }
 
-    private void setUidPolicyUnchecked(int uid, int policy, boolean persist) {
-        final int oldPolicy;
-        synchronized (mRulesLock) {
-            oldPolicy = getUidPolicy(uid);
-            mUidPolicy.put(uid, policy);
+    @Override
+    public void addUidPolicy(int uid, int policy) {
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
 
-            // uid policy changed, recompute rules and persist policy.
-            updateRulesForUidLocked(uid);
-            if (persist) {
-                writePolicyLocked();
+        if (!UserHandle.isApp(uid)) {
+            throw new IllegalArgumentException("cannot apply policy to UID " + uid);
+        }
+
+        synchronized (mRulesLock) {
+            final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
+            policy |= oldPolicy;
+            if (oldPolicy != policy) {
+                setUidPolicyUncheckedLocked(uid, policy, true);
             }
         }
     }
 
     @Override
+    public void removeUidPolicy(int uid, int policy) {
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+        if (!UserHandle.isApp(uid)) {
+            throw new IllegalArgumentException("cannot apply policy to UID " + uid);
+        }
+
+        synchronized (mRulesLock) {
+            final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
+            policy = oldPolicy & ~policy;
+            if (oldPolicy != policy) {
+                setUidPolicyUncheckedLocked(uid, policy, true);
+            }
+        }
+    }
+
+    private void setUidPolicyUncheckedLocked(int uid, int policy, boolean persist) {
+        mUidPolicy.put(uid, policy);
+
+        // uid policy changed, recompute rules and persist policy.
+        updateRulesForUidLocked(uid);
+        if (persist) {
+            writePolicyLocked();
+        }
+    }
+
+    @Override
     public int getUidPolicy(int uid) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
 
@@ -1389,6 +1494,20 @@
         return uids;
     }
 
+    @Override
+    public int[] getPowerSaveAppIdWhitelist() {
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+        synchronized (mRulesLock) {
+            int size = mPowerSaveWhitelistAppIds.size();
+            int[] appids = new int[size];
+            for (int i = 0; i < size; i++) {
+                appids[i] = mPowerSaveWhitelistAppIds.keyAt(i);
+            }
+            return appids;
+        }
+    }
+
     /**
      * Remove any policies associated with given {@link UserHandle}, persisting
      * if any changes are made.
@@ -1515,7 +1634,7 @@
         maybeRefreshTrustedTime();
         synchronized (mRulesLock) {
             mRestrictBackground = restrictBackground;
-            updateRulesForRestrictBackgroundLocked();
+            updateRulesForGlobalChangeLocked(false);
             updateNotificationsLocked();
             writePolicyLocked();
         }
@@ -1534,7 +1653,8 @@
     }
 
     private NetworkPolicy findPolicyForNetworkLocked(NetworkIdentity ident) {
-        for (NetworkPolicy policy : mNetworkPolicy.values()) {
+        for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+            NetworkPolicy policy = mNetworkPolicy.valueAt(i);
             if (policy.template.matches(ident)) {
                 return policy;
             }
@@ -1623,8 +1743,8 @@
 
         synchronized (mRulesLock) {
             if (argSet.contains("--unsnooze")) {
-                for (NetworkPolicy policy : mNetworkPolicy.values()) {
-                    policy.clearSnooze();
+                for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+                    mNetworkPolicy.valueAt(i).clearSnooze();
                 }
 
                 updateNetworkEnabledLocked();
@@ -1637,10 +1757,11 @@
             }
 
             fout.print("Restrict background: "); fout.println(mRestrictBackground);
+            fout.print("Restrict power: "); fout.println(mRestrictPower);
             fout.println("Network policies:");
             fout.increaseIndent();
-            for (NetworkPolicy policy : mNetworkPolicy.values()) {
-                fout.println(policy.toString());
+            for (int i = 0; i < mNetworkPolicy.size(); i++) {
+                fout.println(mNetworkPolicy.valueAt(i).toString());
             }
             fout.decreaseIndent();
 
@@ -1658,6 +1779,20 @@
             }
             fout.decreaseIndent();
 
+            size = mPowerSaveWhitelistAppIds.size();
+            if (size > 0) {
+                fout.println("Power save whitelist app ids:");
+                fout.increaseIndent();
+                for (int i = 0; i < size; i++) {
+                    fout.print("UID=");
+                    fout.print(mPowerSaveWhitelistAppIds.keyAt(i));
+                    fout.print(": ");
+                    fout.print(mPowerSaveWhitelistAppIds.valueAt(i));
+                    fout.println();
+                }
+                fout.decreaseIndent();
+            }
+
             final SparseBooleanArray knownUids = new SparseBooleanArray();
             collectKeys(mUidForeground, knownUids);
             collectKeys(mUidRules, knownUids);
@@ -1753,9 +1888,10 @@
     }
 
     /**
-     * Update rules that might be changed by {@link #mRestrictBackground} value.
+     * Update rules that might be changed by {@link #mRestrictBackground}
+     * or {@link #mRestrictPower} value.
      */
-    private void updateRulesForRestrictBackgroundLocked() {
+    private void updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged) {
         final PackageManager pm = mContext.getPackageManager();
         final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
 
@@ -1774,6 +1910,11 @@
         // limit data usage for some internal system services
         updateRulesForUidLocked(android.os.Process.MEDIA_UID);
         updateRulesForUidLocked(android.os.Process.DRM_UID);
+
+        // If the set of restricted networks may have changed, re-evaluate those.
+        if (restrictedNetworksChanged) {
+            updateNetworkRulesLocked();
+        }
     }
 
     private static boolean isUidValidForRules(int uid) {
@@ -1797,10 +1938,20 @@
         if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
             // uid in background, and policy says to block metered data
             uidRules = RULE_REJECT_METERED;
-        }
-        if (!uidForeground && mRestrictBackground) {
-            // uid in background, and global background disabled
-            uidRules = RULE_REJECT_METERED;
+        } else if (mRestrictBackground) {
+            if (!uidForeground) {
+                // uid in background, and global background disabled
+                uidRules = RULE_REJECT_METERED;
+            }
+        } else if (mRestrictPower) {
+            final boolean whitelisted = mPowerSaveWhitelistAppIds.get(UserHandle.getAppId(uid));
+            if (!whitelisted && !uidForeground
+                    && (uidPolicy & POLICY_ALLOW_BACKGROUND_BATTERY_SAVE) == 0) {
+                // uid is in background, restrict power use mode is on (so we want to
+                // restrict all background network access), and this uid is not on the
+                // white list of those allowed background access.
+                uidRules = RULE_REJECT_METERED;
+            }
         }
 
         // TODO: only dispatch when rules actually change
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index cac27bc..cf32be9 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -36,6 +36,7 @@
 import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.internal.util.ArrayUtils.removeInt;
 
+import android.util.ArrayMap;
 import com.android.internal.R;
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.app.ResolverActivity;
@@ -50,6 +51,7 @@
 import com.android.server.IntentResolver;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
+import com.android.server.SystemConfig;
 import com.android.server.Watchdog;
 import com.android.server.pm.Settings.DatabaseVersion;
 import com.android.server.storage.DeviceStorageMonitorInternal;
@@ -391,17 +393,20 @@
     final Settings mSettings;
     boolean mRestoredSettings;
 
-    // Group-ids that are given to all packages as read from etc/permissions/*.xml.
-    int[] mGlobalGids;
+    // System configuration read by SystemConfig.
+    final int[] mGlobalGids;
+    final SparseArray<HashSet<String>> mSystemPermissions;
+    final HashMap<String, FeatureInfo> mAvailableFeatures;
 
-    // These are the built-in uid -> permission mappings that were read from the
-    // etc/permissions.xml file.
-    final SparseArray<HashSet<String>> mSystemPermissions =
-            new SparseArray<HashSet<String>>();
+    // If mac_permissions.xml was found for seinfo labeling.
+    boolean mFoundPolicyFile;
 
-    static final class SharedLibraryEntry {
-        final String path;
-        final String apk;
+    // If a recursive restorecon of /data/data/<pkg> is needed.
+    private boolean mShouldRestoreconData = SELinuxMMAC.shouldRestorecon();
+
+    public static final class SharedLibraryEntry {
+        public final String path;
+        public final String apk;
 
         SharedLibraryEntry(String _path, String _apk) {
             path = _path;
@@ -409,21 +414,9 @@
         }
     }
 
-    // These are the built-in shared libraries that were read from the
-    // etc/permissions.xml file.
-    final HashMap<String, SharedLibraryEntry> mSharedLibraries
-            = new HashMap<String, SharedLibraryEntry>();
-
-    // These are the features this devices supports that were read from the
-    // etc/permissions.xml file.
-    final HashMap<String, FeatureInfo> mAvailableFeatures =
-            new HashMap<String, FeatureInfo>();
-
-    // If mac_permissions.xml was found for seinfo labeling.
-    boolean mFoundPolicyFile;
-
-    // If a recursive restorecon of /data/data/<pkg> is needed.
-    private boolean mShouldRestoreconData = SELinuxMMAC.shouldRestorecon();
+    // Currently known shared libraries.
+    final HashMap<String, SharedLibraryEntry> mSharedLibraries =
+            new HashMap<String, SharedLibraryEntry>();
 
     // All available activities, for your resolving pleasure.
     final ActivityIntentResolver mActivities =
@@ -1331,6 +1324,11 @@
 
         getDefaultDisplayMetrics(context, mMetrics);
 
+        SystemConfig systemConfig = SystemConfig.getInstance();
+        mGlobalGids = systemConfig.getGlobalGids();
+        mSystemPermissions = systemConfig.getSystemPermissions();
+        mAvailableFeatures = systemConfig.getAvailableFeatures();
+
         synchronized (mInstallLock) {
         // writer
         synchronized (mPackages) {
@@ -1352,12 +1350,26 @@
             sUserManager = new UserManagerService(context, this,
                     mInstallLock, mPackages);
 
-            // Read permissions and features from system
-            readPermissions(Environment.buildPath(
-                    Environment.getRootDirectory(), "etc", "permissions"), false);
-            // Only read features from OEM
-            readPermissions(Environment.buildPath(
-                    Environment.getOemDirectory(), "etc", "permissions"), true);
+            // Propagate permission configuration in to package manager.
+            ArrayMap<String, SystemConfig.PermissionEntry> permConfig
+                    = systemConfig.getPermissions();
+            for (int i=0; i<permConfig.size(); i++) {
+                SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
+                BasePermission bp = mSettings.mPermissions.get(perm.name);
+                if (bp == null) {
+                    bp = new BasePermission(perm.name, null, BasePermission.TYPE_BUILTIN);
+                    mSettings.mPermissions.put(perm.name, bp);
+                }
+                if (perm.gids != null) {
+                    bp.gids = appendInts(bp.gids, perm.gids);
+                }
+            }
+
+            ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
+            for (int i=0; i<libConfig.size(); i++) {
+                mSharedLibraries.put(libConfig.keyAt(i),
+                        new SharedLibraryEntry(libConfig.valueAt(i), null));
+            }
 
             mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
 
@@ -1822,198 +1834,6 @@
         mSettings.removePackageLPw(ps.name);
     }
 
-    void readPermissions(File libraryDir, boolean onlyFeatures) {
-        // Read permissions from .../etc/permission directory.
-        if (!libraryDir.exists() || !libraryDir.isDirectory()) {
-            Slog.w(TAG, "No directory " + libraryDir + ", skipping");
-            return;
-        }
-        if (!libraryDir.canRead()) {
-            Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
-            return;
-        }
-
-        // Iterate over the files in the directory and scan .xml files
-        for (File f : libraryDir.listFiles()) {
-            // We'll read platform.xml last
-            if (f.getPath().endsWith("etc/permissions/platform.xml")) {
-                continue;
-            }
-
-            if (!f.getPath().endsWith(".xml")) {
-                Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
-                continue;
-            }
-            if (!f.canRead()) {
-                Slog.w(TAG, "Permissions library file " + f + " cannot be read");
-                continue;
-            }
-
-            readPermissionsFromXml(f, onlyFeatures);
-        }
-
-        // Read permissions from .../etc/permissions/platform.xml last so it will take precedence
-        final File permFile = new File(Environment.getRootDirectory(),
-                "etc/permissions/platform.xml");
-        readPermissionsFromXml(permFile, onlyFeatures);
-    }
-
-    private void readPermissionsFromXml(File permFile, boolean onlyFeatures) {
-        FileReader permReader = null;
-        try {
-            permReader = new FileReader(permFile);
-        } catch (FileNotFoundException e) {
-            Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
-            return;
-        }
-
-        try {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(permReader);
-
-            XmlUtils.beginDocument(parser, "permissions");
-
-            while (true) {
-                XmlUtils.nextElement(parser);
-                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
-                    break;
-                }
-
-                String name = parser.getName();
-                if ("group".equals(name) && !onlyFeatures) {
-                    String gidStr = parser.getAttributeValue(null, "gid");
-                    if (gidStr != null) {
-                        int gid = Process.getGidForName(gidStr);
-                        mGlobalGids = appendInt(mGlobalGids, gid);
-                    } else {
-                        Slog.w(TAG, "<group> without gid at "
-                                + parser.getPositionDescription());
-                    }
-
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-                } else if ("permission".equals(name) && !onlyFeatures) {
-                    String perm = parser.getAttributeValue(null, "name");
-                    if (perm == null) {
-                        Slog.w(TAG, "<permission> without name at "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                    perm = perm.intern();
-                    readPermission(parser, perm);
-
-                } else if ("assign-permission".equals(name) && !onlyFeatures) {
-                    String perm = parser.getAttributeValue(null, "name");
-                    if (perm == null) {
-                        Slog.w(TAG, "<assign-permission> without name at "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                    String uidStr = parser.getAttributeValue(null, "uid");
-                    if (uidStr == null) {
-                        Slog.w(TAG, "<assign-permission> without uid at "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                    int uid = Process.getUidForName(uidStr);
-                    if (uid < 0) {
-                        Slog.w(TAG, "<assign-permission> with unknown uid \""
-                                + uidStr + "\" at "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                    perm = perm.intern();
-                    HashSet<String> perms = mSystemPermissions.get(uid);
-                    if (perms == null) {
-                        perms = new HashSet<String>();
-                        mSystemPermissions.put(uid, perms);
-                    }
-                    perms.add(perm);
-                    XmlUtils.skipCurrentTag(parser);
-
-                } else if ("library".equals(name) && !onlyFeatures) {
-                    String lname = parser.getAttributeValue(null, "name");
-                    String lfile = parser.getAttributeValue(null, "file");
-                    if (lname == null) {
-                        Slog.w(TAG, "<library> without name at "
-                                + parser.getPositionDescription());
-                    } else if (lfile == null) {
-                        Slog.w(TAG, "<library> without file at "
-                                + parser.getPositionDescription());
-                    } else {
-                        //Log.i(TAG, "Got library " + lname + " in " + lfile);
-                        mSharedLibraries.put(lname, new SharedLibraryEntry(lfile, null));
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-
-                } else if ("feature".equals(name)) {
-                    String fname = parser.getAttributeValue(null, "name");
-                    if (fname == null) {
-                        Slog.w(TAG, "<feature> without name at "
-                                + parser.getPositionDescription());
-                    } else {
-                        //Log.i(TAG, "Got feature " + fname);
-                        FeatureInfo fi = new FeatureInfo();
-                        fi.name = fname;
-                        mAvailableFeatures.put(fname, fi);
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-
-                } else {
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-                }
-
-            }
-            permReader.close();
-        } catch (XmlPullParserException e) {
-            Slog.w(TAG, "Got execption parsing permissions.", e);
-        } catch (IOException e) {
-            Slog.w(TAG, "Got execption parsing permissions.", e);
-        }
-    }
-
-    void readPermission(XmlPullParser parser, String name)
-            throws IOException, XmlPullParserException {
-
-        name = name.intern();
-
-        BasePermission bp = mSettings.mPermissions.get(name);
-        if (bp == null) {
-            bp = new BasePermission(name, null, BasePermission.TYPE_BUILTIN);
-            mSettings.mPermissions.put(name, bp);
-        }
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-               && (type != XmlPullParser.END_TAG
-                       || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG
-                    || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            if ("group".equals(tagName)) {
-                String gidStr = parser.getAttributeValue(null, "gid");
-                if (gidStr != null) {
-                    int gid = Process.getGidForName(gidStr);
-                    bp.gids = appendInt(bp.gids, gid);
-                } else {
-                    Slog.w(TAG, "<group> without gid at "
-                            + parser.getPositionDescription());
-                }
-            }
-            XmlUtils.skipCurrentTag(parser);
-        }
-    }
-
     static int[] appendInts(int[] cur, int[] add) {
         if (add == null) return cur;
         if (cur == null) return add;
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index c78249b..81302b9 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -346,31 +346,21 @@
      */
     public static boolean assignSeinfoValue(PackageParser.Package pkg) {
 
-        /*
-         * Non system installed apps should be treated the same. This
-         * means that any post-loaded apk will be assigned the default
-         * tag, if one exists in the policy, else null, without respect
-         * to the signing key.
-         */
-        if (((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) ||
-            ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)) {
+        // We just want one of the signatures to match.
+        for (Signature s : pkg.mSignatures) {
+            if (s == null)
+                continue;
 
-            // We just want one of the signatures to match.
-            for (Signature s : pkg.mSignatures) {
-                if (s == null)
-                    continue;
+            Policy policy = sSigSeinfo.get(s);
+            if (policy != null) {
+                String seinfo = policy.checkPolicy(pkg.packageName);
+                if (seinfo != null) {
+                    pkg.applicationInfo.seinfo = seinfo;
+                    if (DEBUG_POLICY_INSTALL)
+                        Slog.i(TAG, "package (" + pkg.packageName +
+                               ") labeled with seinfo=" + seinfo);
 
-                Policy policy = sSigSeinfo.get(s);
-                if (policy != null) {
-                    String seinfo = policy.checkPolicy(pkg.packageName);
-                    if (seinfo != null) {
-                        pkg.applicationInfo.seinfo = seinfo;
-                        if (DEBUG_POLICY_INSTALL)
-                            Slog.i(TAG, "package (" + pkg.packageName +
-                                   ") labeled with seinfo=" + seinfo);
-
-                        return true;
-                    }
+                    return true;
                 }
             }
         }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0d05c5f..52ca098 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -404,6 +404,9 @@
         boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
 
         try {
+            Slog.i(TAG, "Reading configuration...");
+            SystemConfig.getInstance();
+
             Slog.i(TAG, "Scheduling Policy");
             ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
 
diff --git a/telecomm/java/android/telecomm/CallVideoClient.java b/telecomm/java/android/telecomm/CallVideoClient.java
index 9e3c48d..76b28fa 100644
--- a/telecomm/java/android/telecomm/CallVideoClient.java
+++ b/telecomm/java/android/telecomm/CallVideoClient.java
@@ -17,6 +17,7 @@
 package android.telecomm;
 
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 
@@ -66,22 +67,22 @@
      */
     public static final int SESSION_MODIFY_REQUEST_INVALID = 3;
 
-    private static final int MSG_ON_RECEIVE_SESSION_MODIFY_REQUEST = 1;
-    private static final int MSG_ON_RECEIVE_SESSION_MODIFY_RESPONSE = 2;
-    private static final int MSG_ON_CALL_SESSION_EVENT = 3;
-    private static final int MSG_ON_UPDATED_PEER_DIMENSIONS = 4;
-    private static final int MSG_ON_UPDATE_CALL_DATA_USAGE = 5;
-    private static final int MSG_ON_CAMERA_CAPABILITIES_CHANGE = 6;
+    private static final int MSG_RECEIVE_SESSION_MODIFY_REQUEST = 1;
+    private static final int MSG_RECEIVE_SESSION_MODIFY_RESPONSE = 2;
+    private static final int MSG_HANDLE_CALL_SESSION_EVENT = 3;
+    private static final int MSG_UPDATE_PEER_DIMENSIONS = 4;
+    private static final int MSG_UPDATE_CALL_DATA_USAGE = 5;
+    private static final int MSG_HANDLE_CAMERA_CAPABILITIES_CHANGE = 6;
 
     /** Default Handler used to consolidate binder method calls onto a single thread. */
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case MSG_ON_RECEIVE_SESSION_MODIFY_REQUEST:
+                case MSG_RECEIVE_SESSION_MODIFY_REQUEST:
                     onReceiveSessionModifyRequest((VideoCallProfile) msg.obj);
                     break;
-                case MSG_ON_RECEIVE_SESSION_MODIFY_RESPONSE: {
+                case MSG_RECEIVE_SESSION_MODIFY_RESPONSE: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
                         int status = (int) args.arg1;
@@ -95,25 +96,25 @@
                     }
                     break;
                 }
-                case MSG_ON_CALL_SESSION_EVENT:
-                    onCallSessionEvent((int) msg.obj);
+                case MSG_HANDLE_CALL_SESSION_EVENT:
+                    onHandleCallSessionEvent((int) msg.obj);
                     break;
-                case MSG_ON_UPDATED_PEER_DIMENSIONS: {
+                case MSG_UPDATE_PEER_DIMENSIONS: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
                         int width = (int) args.arg1;
                         int height = (int) args.arg2;
-                        onUpdatedPeerDimensions(width, height);
+                        onUpdatePeerDimensions(width, height);
                     } finally {
                         args.recycle();
                     }
                     break;
                 }
-                case MSG_ON_UPDATE_CALL_DATA_USAGE:
+                case MSG_UPDATE_CALL_DATA_USAGE:
                     onUpdateCallDataUsage(msg.arg1);
                     break;
-                case MSG_ON_CAMERA_CAPABILITIES_CHANGE:
-                    onCameraCapabilitiesChange((CallCameraCapabilities) msg.obj);
+                case MSG_HANDLE_CAMERA_CAPABILITIES_CHANGE:
+                    onHandleCameraCapabilitiesChange((CallCameraCapabilities) msg.obj);
                     break;
                 default:
                     break;
@@ -126,42 +127,42 @@
      */
     private final class CallVideoClientBinder extends ICallVideoClient.Stub {
         @Override
-        public void onReceiveSessionModifyRequest(VideoCallProfile videoCallProfile) {
-            mHandler.obtainMessage(MSG_ON_RECEIVE_SESSION_MODIFY_REQUEST,
+        public void receiveSessionModifyRequest(VideoCallProfile videoCallProfile) {
+            mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_REQUEST,
                     videoCallProfile).sendToTarget();
         }
 
         @Override
-        public void onReceiveSessionModifyResponse(int status,
+        public void receiveSessionModifyResponse(int status,
                 VideoCallProfile requestProfile, VideoCallProfile responseProfile) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = status;
             args.arg2 = requestProfile;
             args.arg3 = responseProfile;
-            mHandler.obtainMessage(MSG_ON_RECEIVE_SESSION_MODIFY_RESPONSE, args).sendToTarget();
+            mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_RESPONSE, args).sendToTarget();
         }
 
         @Override
-        public void onCallSessionEvent(int event) {
-            mHandler.obtainMessage(MSG_ON_CALL_SESSION_EVENT, event).sendToTarget();
+        public void handleCallSessionEvent(int event) {
+            mHandler.obtainMessage(MSG_HANDLE_CALL_SESSION_EVENT, event).sendToTarget();
         }
 
         @Override
-        public void onUpdatedPeerDimensions(int width, int height) {
+        public void updatePeerDimensions(int width, int height) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = width;
             args.arg2 = height;
-            mHandler.obtainMessage(MSG_ON_UPDATED_PEER_DIMENSIONS, args).sendToTarget();
+            mHandler.obtainMessage(MSG_UPDATE_PEER_DIMENSIONS, args).sendToTarget();
         }
 
         @Override
-        public void onUpdateCallDataUsage(int dataUsage) {
-            mHandler.obtainMessage(MSG_ON_UPDATE_CALL_DATA_USAGE, dataUsage).sendToTarget();
+        public void updateCallDataUsage(int dataUsage) {
+            mHandler.obtainMessage(MSG_UPDATE_CALL_DATA_USAGE, dataUsage).sendToTarget();
         }
 
         @Override
-        public void onCameraCapabilitiesChange(CallCameraCapabilities cameraCapabilities) {
-            mHandler.obtainMessage(MSG_ON_CAMERA_CAPABILITIES_CHANGE,
+        public void handleCameraCapabilitiesChange(CallCameraCapabilities cameraCapabilities) {
+            mHandler.obtainMessage(MSG_HANDLE_CAMERA_CAPABILITIES_CHANGE,
                     cameraCapabilities).sendToTarget();
         }
     }
@@ -173,21 +174,19 @@
     }
 
     /**
-     * Retrieves the binder.
-     *
-     * @return The binder.
+     * Returns binder object which can be used across IPC methods.
      * @hide
      */
-    public final CallVideoClientBinder getBinder() {
+    public final IBinder getBinder() {
         return mBinder;
     }
 
     /**
      * Called when a session modification request is received from the remote device.
-     * The remote request is sent via {@link CallVideoProvider#sendSessionModifyRequest}.
+     * The remote request is sent via {@link CallVideoProvider#onSendSessionModifyRequest}.
      * The InCall UI is responsible for potentially prompting the user whether they wish to accept
      * the new call profile (e.g. prompt user if they wish to accept an upgrade from an audio to a
-     * video call) and should call {@link CallVideoProvider#sendSessionModifyResponse} to indicate
+     * video call) and should call {@link CallVideoProvider#onSendSessionModifyResponse} to indicate
      * the video settings the user has agreed to.
      *
      * @param videoCallProfile The requested video call profile.
@@ -197,7 +196,7 @@
     /**
      * Called when a response to a session modification request is received from the remote device.
      * The remote InCall UI sends the response using
-     * {@link CallVideoProvider#sendSessionModifyResponse}.
+     * {@link CallVideoProvider#onSendSessionModifyResponse}.
      *
      * @param status Status of the session modify request.  Valid values are
      *               {@link CallVideoClient#SESSION_MODIFY_REQUEST_SUCCESS},
@@ -219,7 +218,7 @@
      *
      * @param event The event.
      */
-    public abstract void onCallSessionEvent(int event);
+    public abstract void onHandleCallSessionEvent(int event);
 
     /**
      * Handles a change to the video dimensions from the remote caller (peer).  This could happen
@@ -228,7 +227,7 @@
      * @param width  The updated peer video width.
      * @param height The updated peer video height.
      */
-    public abstract void onUpdatedPeerDimensions(int width, int height);
+    public abstract void onUpdatePeerDimensions(int width, int height);
 
     /**
      * Handles an update to the total data used for the current session.
@@ -242,6 +241,6 @@
      *
      * @param callCameraCapabilities The changed camera capabilities.
      */
-    public abstract void onCameraCapabilitiesChange(CallCameraCapabilities callCameraCapabilities);
+    public abstract void onHandleCameraCapabilitiesChange(CallCameraCapabilities callCameraCapabilities);
 }
 
diff --git a/telecomm/java/android/telecomm/CallVideoProvider.java b/telecomm/java/android/telecomm/CallVideoProvider.java
index 2f16112..2a04724 100644
--- a/telecomm/java/android/telecomm/CallVideoProvider.java
+++ b/telecomm/java/android/telecomm/CallVideoProvider.java
@@ -17,22 +17,26 @@
 package android.telecomm;
 
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
+import android.os.RemoteException;
 import android.view.Surface;
 
+import com.android.internal.telecomm.ICallVideoClient;
 import com.android.internal.telecomm.ICallVideoProvider;
 
 public abstract class CallVideoProvider {
-    private static final int MSG_SET_CAMERA = 1;
-    private static final int MSG_SET_PREVIEW_SURFACE = 2;
-    private static final int MSG_SET_DISPLAY_SURFACE = 3;
-    private static final int MSG_SET_DEVICE_ORIENTATION = 4;
-    private static final int MSG_SET_ZOOM = 5;
-    private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 6;
-    private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 7;
-    private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 8;
-    private static final int MSG_REQUEST_CALL_DATA_USAGE = 9;
-    private static final int MSG_SET_PAUSE_IMAGE = 10;
+    private static final int MSG_SET_CALL_VIDEO_CLIENT = 1;
+    private static final int MSG_SET_CAMERA = 2;
+    private static final int MSG_SET_PREVIEW_SURFACE = 3;
+    private static final int MSG_SET_DISPLAY_SURFACE = 4;
+    private static final int MSG_SET_DEVICE_ORIENTATION = 5;
+    private static final int MSG_SET_ZOOM = 6;
+    private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7;
+    private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8;
+    private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9;
+    private static final int MSG_REQUEST_CALL_DATA_USAGE = 10;
+    private static final int MSG_SET_PAUSE_IMAGE = 11;
 
     /**
      * Default handler used to consolidate binder method calls onto a single thread.
@@ -41,35 +45,45 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
+                case MSG_SET_CALL_VIDEO_CLIENT:
+                    try {
+                        ICallVideoClient callVideoClient =
+                                ICallVideoClient.Stub.asInterface((IBinder) msg.obj);
+                        RemoteCallVideoClient remoteCallVideoClient =
+                                new RemoteCallVideoClient(callVideoClient);
+                        onSetCallVideoClient(remoteCallVideoClient);
+                    } catch (RemoteException ignored) {
+                    }
+                    break;
                 case MSG_SET_CAMERA:
-                    setCamera((String) msg.obj);
+                    onSetCamera((String) msg.obj);
                     break;
                 case MSG_SET_PREVIEW_SURFACE:
-                    setPreviewSurface((Surface) msg.obj);
+                    onSetPreviewSurface((Surface) msg.obj);
                     break;
                 case MSG_SET_DISPLAY_SURFACE:
-                    setDisplaySurface((Surface) msg.obj);
+                    onSetDisplaySurface((Surface) msg.obj);
                     break;
                 case MSG_SET_DEVICE_ORIENTATION:
-                    setDeviceOrientation(msg.arg1);
+                    onSetDeviceOrientation(msg.arg1);
                     break;
                 case MSG_SET_ZOOM:
-                    setZoom((Float) msg.obj);
+                    onSetZoom((Float) msg.obj);
                     break;
                 case MSG_SEND_SESSION_MODIFY_REQUEST:
-                    sendSessionModifyRequest((VideoCallProfile) msg.obj);
+                    onSendSessionModifyRequest((VideoCallProfile) msg.obj);
                     break;
                 case MSG_SEND_SESSION_MODIFY_RESPONSE:
-                    sendSessionModifyResponse((VideoCallProfile) msg.obj);
+                    onSendSessionModifyResponse((VideoCallProfile) msg.obj);
                     break;
                 case MSG_REQUEST_CAMERA_CAPABILITIES:
-                    requestCameraCapabilities();
+                    onRequestCameraCapabilities();
                     break;
                 case MSG_REQUEST_CALL_DATA_USAGE:
-                    requestCallDataUsage();
+                    onRequestCallDataUsage();
                     break;
                 case MSG_SET_PAUSE_IMAGE:
-                    setPauseImage((String) msg.obj);
+                    onSetPauseImage((String) msg.obj);
                     break;
                 default:
                     break;
@@ -81,6 +95,11 @@
      * Default ICallVideoProvider implementation.
      */
     private final class CallVideoProviderBinder extends ICallVideoProvider.Stub {
+        public void setCallVideoClient(IBinder callVideoClientBinder) {
+            mMessageHandler.obtainMessage(
+                    MSG_SET_CALL_VIDEO_CLIENT, callVideoClientBinder).sendToTarget();
+        }
+
         public void setCamera(String cameraId) {
             mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget();
         }
@@ -102,13 +121,13 @@
         }
 
         public void sendSessionModifyRequest(VideoCallProfile requestProfile) {
-            mMessageHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST,
-                    requestProfile).sendToTarget();
+            mMessageHandler.obtainMessage(
+                    MSG_SEND_SESSION_MODIFY_REQUEST, requestProfile).sendToTarget();
         }
 
         public void sendSessionModifyResponse(VideoCallProfile responseProfile) {
-            mMessageHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_RESPONSE,
-                    responseProfile).sendToTarget();
+            mMessageHandler.obtainMessage(
+                    MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget();
         }
 
         public void requestCameraCapabilities() {
@@ -140,11 +159,19 @@
     }
 
     /**
+     * Sets a remote interface for invoking callback methods in the InCallUI after performing
+     * telephony actions.
+     *
+     * @param callVideoClient The call video client.
+     */
+    public abstract void onSetCallVideoClient(RemoteCallVideoClient callVideoClient);
+
+    /**
      * Sets the camera to be used for video recording in a video call.
      *
      * @param cameraId The id of the camera.
      */
-    public abstract void setCamera(String cameraId);
+    public abstract void onSetCamera(String cameraId);
 
     /**
      * Sets the surface to be used for displaying a preview of what the user's camera is
@@ -153,14 +180,14 @@
      *
      * @param surface The surface.
      */
-    public abstract void setPreviewSurface(Surface surface);
+    public abstract void onSetPreviewSurface(Surface surface);
 
     /**
      * Sets the surface to be used for displaying the video received from the remote device.
      *
      * @param surface The surface.
      */
-    public abstract void setDisplaySurface(Surface surface);
+    public abstract void onSetDisplaySurface(Surface surface);
 
     /**
      * Sets the device orientation, in degrees.  Assumes that a standard portrait orientation of the
@@ -168,14 +195,14 @@
      *
      * @param rotation The device orientation, in degrees.
      */
-    public abstract void setDeviceOrientation(int rotation);
+    public abstract void onSetDeviceOrientation(int rotation);
 
     /**
      * Sets camera zoom ratio.
      *
      * @param value The camera zoom ratio.
      */
-    public abstract void setZoom(float value);
+    public abstract void onSetZoom(float value);
 
     /**
      * Issues a request to modify the properties of the current session.  The request is sent to
@@ -186,7 +213,7 @@
      *
      * @param requestProfile The requested call video properties.
      */
-    public abstract void sendSessionModifyRequest(VideoCallProfile requestProfile);
+    public abstract void onSendSessionModifyRequest(VideoCallProfile requestProfile);
 
     /**
      * Provides a response to a request to change the current call session video
@@ -198,21 +225,21 @@
      *
      * @param responseProfile The response call video properties.
      */
-    public abstract void sendSessionModifyResponse(VideoCallProfile responseProfile);
+    public abstract void onSendSessionModifyResponse(VideoCallProfile responseProfile);
 
     /**
      * Issues a request to the video provider to retrieve the camera capabilities.
      * Camera capabilities are reported back to the caller via
-     * {@link CallVideoClient#onCameraCapabilitiesChange(CallCameraCapabilities)}.
+     * {@link CallVideoClient#onHandleCameraCapabilitiesChange(CallCameraCapabilities)}.
      */
-    public abstract void requestCameraCapabilities();
+    public abstract void onRequestCameraCapabilities();
 
     /**
      * Issues a request to the video telephony framework to retrieve the cumulative data usage for
      * the current call.  Data usage is reported back to the caller via
      * {@link CallVideoClient#onUpdateCallDataUsage}.
      */
-    public abstract void requestCallDataUsage();
+    public abstract void onRequestCallDataUsage();
 
     /**
      * Provides the video telephony framework with the URI of an image to be displayed to remote
@@ -220,5 +247,5 @@
      *
      * @param uri URI of image to display.
      */
-    public abstract void setPauseImage(String uri);
+    public abstract void onSetPauseImage(String uri);
 }
diff --git a/telecomm/java/android/telecomm/RemoteCallVideoClient.java b/telecomm/java/android/telecomm/RemoteCallVideoClient.java
new file mode 100644
index 0000000..f0a3afc
--- /dev/null
+++ b/telecomm/java/android/telecomm/RemoteCallVideoClient.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecomm;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telecomm.CallCameraCapabilities;
+import android.telecomm.VideoCallProfile;
+
+import com.android.internal.telecomm.ICallVideoClient;
+
+public class RemoteCallVideoClient implements IBinder.DeathRecipient {
+    private final ICallVideoClient mCallVideoClient;
+
+    RemoteCallVideoClient(ICallVideoClient callVideoProvider) throws RemoteException {
+        mCallVideoClient = callVideoProvider;
+        mCallVideoClient.asBinder().linkToDeath(this, 0);
+    }
+
+    @Override
+    public void binderDied() {
+        mCallVideoClient.asBinder().unlinkToDeath(this, 0);
+    }
+
+    public void receiveSessionModifyRequest(VideoCallProfile videoCallProfile)
+            throws RemoteException {
+        mCallVideoClient.receiveSessionModifyRequest(videoCallProfile);
+    }
+
+    public void receiveSessionModifyResponse(int status, VideoCallProfile requestedProfile,
+            VideoCallProfile responseProfile) throws RemoteException {
+        mCallVideoClient.receiveSessionModifyResponse(status, requestedProfile, responseProfile);
+    }
+
+    public void handleCallSessionEvent(int event) throws RemoteException {
+        mCallVideoClient.handleCallSessionEvent(event);
+    }
+
+    public void updatePeerDimensions(int width, int height) throws RemoteException {
+        mCallVideoClient.updatePeerDimensions(width, height);
+    }
+
+    public void updateCallDataUsage(int dataUsage) throws RemoteException {
+        mCallVideoClient.updateCallDataUsage(dataUsage);
+    }
+
+    public void handleCameraCapabilitiesChange(CallCameraCapabilities callCameraCapabilities)
+            throws RemoteException {
+        mCallVideoClient.handleCameraCapabilitiesChange(callCameraCapabilities);
+    }
+}
\ No newline at end of file
diff --git a/telecomm/java/android/telecomm/RemoteCallVideoProvider.java b/telecomm/java/android/telecomm/RemoteCallVideoProvider.java
index 872085a..4a226a9 100644
--- a/telecomm/java/android/telecomm/RemoteCallVideoProvider.java
+++ b/telecomm/java/android/telecomm/RemoteCallVideoProvider.java
@@ -18,10 +18,11 @@
 
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.view.Surface;
 
+import com.android.internal.telecomm.ICallVideoClient;
 import com.android.internal.telecomm.ICallVideoProvider;
 
-
 public class RemoteCallVideoProvider implements IBinder.DeathRecipient {
     private final ICallVideoProvider mCallVideoProvider;
 
@@ -35,12 +36,47 @@
         mCallVideoProvider.asBinder().unlinkToDeath(this, 0);
     }
 
-    /**
-     * Sets the camera to be used for video recording in a video call, using the binder.
-     *
-     * @param cameraId The id of the camera.
-     */
+    public void setCallVideoClient(CallVideoClient callVideoClient) throws RemoteException {
+        mCallVideoProvider.setCallVideoClient(callVideoClient.getBinder());
+    }
+
     public void setCamera(String cameraId) throws RemoteException {
         mCallVideoProvider.setCamera(cameraId);
     }
-}
+
+    public void setPreviewSurface(Surface surface) throws RemoteException {
+        mCallVideoProvider.setPreviewSurface(surface);
+    }
+
+    public void setDisplaySurface(Surface surface) throws RemoteException {
+        mCallVideoProvider.setDisplaySurface(surface);
+    }
+
+    public void setDeviceOrientation(int rotation) throws RemoteException {
+        mCallVideoProvider.setDeviceOrientation(rotation);
+    }
+
+    public void setZoom(float value) throws RemoteException {
+        mCallVideoProvider.setZoom(value);
+    }
+
+    public void sendSessionModifyRequest(VideoCallProfile requestProfile) throws RemoteException {
+        mCallVideoProvider.sendSessionModifyRequest(requestProfile);
+    }
+
+    public void sendSessionModifyResponse(VideoCallProfile responseProfile) throws RemoteException {
+        mCallVideoProvider.sendSessionModifyResponse(responseProfile);
+    }
+
+    public void requestCameraCapabilities() throws RemoteException {
+        mCallVideoProvider.requestCameraCapabilities();
+    }
+
+    public void requestCallDataUsage() throws RemoteException {
+        mCallVideoProvider.requestCallDataUsage();
+    }
+
+    public void onSetPauseImage(String uri) throws RemoteException {
+        mCallVideoProvider.setPauseImage(uri);
+    }
+}
\ No newline at end of file
diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java
index a0abc28..6bb75be 100644
--- a/telecomm/java/android/telecomm/TelecommManager.java
+++ b/telecomm/java/android/telecomm/TelecommManager.java
@@ -1,17 +1,15 @@
 /*
  * Copyright (C) 2014 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
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
  */
 
 package android.telecomm;
@@ -62,14 +60,111 @@
     @SystemApi
     public ComponentName getDefaultPhoneApp() {
         try {
-            return getTelecommService().getDefaultPhoneApp();
+            if (isServiceConnected()) {
+                return getTelecommService().getDefaultPhoneApp();
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException attempting to get the default phone app.", e);
         }
         return null;
     }
 
+    /**
+     * Returns whether there is an ongoing phone call (can be in dialing, ringing, active or holding
+     * states).
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isInAPhoneCall() {
+        try {
+            if (isServiceConnected()) {
+                return getTelecommService().isInAPhoneCall();
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException attempting to get default phone app.", e);
+        }
+        return false;
+    }
+
+    /**
+     * Returns whether there currently exists is a ringing incoming-call.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isRinging() {
+        try {
+            if (isServiceConnected()) {
+                return getTelecommService().isRinging();
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException attempting to get ringing state of phone app.", e);
+        }
+        return false;
+    }
+
+    /**
+     * Ends an ongoing call. TODO(santoscordon): L-release - need to convert all invocations of
+     * ITelephony#endCall to use this method (clockwork & gearhead).
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean endCall() {
+        try {
+            if (isServiceConnected()) {
+                return getTelecommService().endCall();
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelecommService#endCall", e);
+        }
+        return false;
+    }
+
+    /**
+     * If there is a ringing incoming call, this method accepts the call on behalf of the user.
+     * TODO(santoscordon): L-release - need to convert all invocation of
+     * ITelephony#answerRingingCall to use this method (clockwork & gearhead).
+     *
+     * @hide
+     */
+    @SystemApi
+    public void acceptRingingCall() {
+        try {
+            if (isServiceConnected()) {
+                getTelecommService().acceptRingingCall();
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelecommService#acceptRingingCall", e);
+        }
+    }
+
+    /**
+     * Silences the ringer if a ringing call exists.
+     *
+     * @hide
+     */
+    @SystemApi
+    public void silenceRinger() {
+        try {
+            if (isServiceConnected()) {
+                getTelecommService().silenceRinger();
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelecommService#silenceRinger", e);
+        }
+    }
+
     private ITelecommService getTelecommService() {
         return ITelecommService.Stub.asInterface(ServiceManager.getService(TELECOMM_SERVICE_NAME));
     }
+
+    private boolean isServiceConnected() {
+        boolean isConnected = getTelecommService() != null;
+        if (!isConnected) {
+            Log.w(TAG, "Telecomm Service not found.");
+        }
+        return isConnected;
+    }
 }
diff --git a/telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl b/telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl
index 0a854a1..2689561 100644
--- a/telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl
@@ -29,16 +29,16 @@
   */
  oneway interface ICallVideoClient {
 
-     void onReceiveSessionModifyRequest(in VideoCallProfile videoCallProfile);
+     void receiveSessionModifyRequest(in VideoCallProfile videoCallProfile);
 
-     void onReceiveSessionModifyResponse(int status, in VideoCallProfile requestedProfile,
+     void receiveSessionModifyResponse(int status, in VideoCallProfile requestedProfile,
             in VideoCallProfile responseProfile);
 
-     void onCallSessionEvent(int event);
+     void handleCallSessionEvent(int event);
 
-     void onUpdatedPeerDimensions(int width, int height);
+     void updatePeerDimensions(int width, int height);
 
-     void onUpdateCallDataUsage(int dataUsage);
+     void updateCallDataUsage(int dataUsage);
 
-     void onCameraCapabilitiesChange(in CallCameraCapabilities callCameraCapabilities);
+     void handleCameraCapabilitiesChange(in CallCameraCapabilities callCameraCapabilities);
  }
diff --git a/telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl b/telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl
index f6587b7..860a431 100644
--- a/telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl
@@ -19,12 +19,16 @@
 import android.view.Surface;
 import android.telecomm.VideoCallProfile;
 
+import com.android.internal.telecomm.ICallVideoClient;
+
 /**
  * Internal remote interface for a call video provider.
  * @see android.telecomm.CallVideoProvider
  * @hide
  */
 oneway interface ICallVideoProvider {
+    void setCallVideoClient(IBinder callVideoClient);
+
     void setCamera(String cameraId);
 
     void setPreviewSurface(in Surface surface);
diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
index 2ae5768..65389df 100644
--- a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
@@ -25,16 +25,6 @@
  * {@hide}
  */
 interface ITelecommService {
-
-    /**
-     * Silence the ringer if an incoming call is currently ringing.
-     * (If vibrating, stop the vibrator also.)
-     *
-     * It's safe to call this if the ringer has already been silenced, or
-     * even if there's no incoming call.  (If so, this method will do nothing.)
-     */
-    void silenceRinger();
-
     /**
      * Brings the in-call screen to the foreground if there is an active call.
      *
@@ -61,4 +51,33 @@
      * Returns the component name of the default phone application.
      */
     ComponentName getDefaultPhoneApp();
+
+    //
+    // Internal system apis relating to call management.
+    //
+
+    /**
+     * @see TelecommManager#silenceRinger
+     */
+    void silenceRinger();
+
+    /**
+     * @see TelecommManager#isInAPhoneCall
+     */
+    boolean isInAPhoneCall();
+
+    /**
+     * @see TelecomManager#isRinging
+     */
+    boolean isRinging();
+
+    /**
+     * @see TelecommManager#endCall
+     */
+    boolean endCall();
+
+    /**
+     * @see TelecommManager#acceptRingingCall
+     */
+    void acceptRingingCall();
 }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 124a8ec..0e5b0e6 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2793,6 +2793,25 @@
     }
 
     /**
+     * Set the CDMA subscription source.
+     * Used for device supporting both NV and RUIM for CDMA.
+     *
+     * @param subscriptionType the subscription type, 0 for RUIM, 1 for NV.
+     * @return true on success; false on any failure.
+     * @hide
+     */
+    public boolean setCdmaSubscription(int subscriptionType) {
+        try {
+            return getITelephony().setCdmaSubscription(subscriptionType);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "setCdmaSubscription RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "setCdmaSubscription NPE", ex);
+        }
+        return false;
+    }
+
+    /**
      * Expose the rest of ITelephony to @SystemApi
      */
 
diff --git a/telephony/java/com/android/ims/internal/IImsUt.aidl b/telephony/java/com/android/ims/internal/IImsUt.aidl
index 32929ed..f9375e4 100644
--- a/telephony/java/com/android/ims/internal/IImsUt.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUt.aidl
@@ -47,6 +47,26 @@
     int queryCallWaiting();
 
     /**
+     * Retrieves the default CLIR setting.
+     */
+    int queryCLIR();
+
+    /**
+     * Retrieves the CLIP call setting.
+     */
+    int queryCLIP();
+
+    /**
+     * Retrieves the COLR call setting.
+     */
+    int queryCOLR();
+
+    /**
+     * Retrieves the COLP call setting.
+     */
+    int queryCOLP();
+
+    /**
      * Updates or retrieves the supplementary service configuration.
      */
     int transact(in Bundle ssInfo);
@@ -67,6 +87,26 @@
     int updateCallWaiting(boolean enable);
 
     /**
+     * Updates the configuration of the CLIR supplementary service.
+     */
+    int updateCLIR(int clirMode);
+
+    /**
+     * Updates the configuration of the CLIP supplementary service.
+     */
+    int updateCLIP(boolean enable);
+
+    /**
+     * Updates the configuration of the COLR supplementary service.
+     */
+    int updateCOLR(int presentation);
+
+    /**
+     * Updates the configuration of the COLP supplementary service.
+     */
+    int updateCOLP(boolean enable);
+
+    /**
      * Sets the listener.
      */
     void setListener(in IImsUtListener listener);
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index beee616..237e7f3 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -606,6 +606,15 @@
     boolean setPreferredNetworkType(int networkType);
 
     /**
+     * Set the CDMA subscription source.
+     * Used for device supporting both NV and RUIM for CDMA.
+     *
+     * @param subscriptionType the subscription type, 0 for RUIM, 1 for NV.
+     * @return true on success; false on any failure.
+     */
+    boolean setCdmaSubscription(int subscriptionType);
+
+    /**
      * User enable/disable Mobile Data.
      *
      * @param enable true to turn on, else false
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLDepthTestActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLDepthTestActivity.java
index 2ea5219..1bb6d0c 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GLDepthTestActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLDepthTestActivity.java
@@ -22,6 +22,8 @@
 import android.content.pm.ConfigurationInfo;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.opengl.EGL14;
+import android.opengl.EGLDisplay;
 import android.opengl.GLES20;
 import android.opengl.GLSurfaceView;
 import android.opengl.GLUtils;
@@ -29,7 +31,7 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.util.Log;
-
+import android.view.MotionEvent;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -54,7 +56,8 @@
             // 2.0-compatible
             // context, and set an OpenGL ES 2.0-compatible renderer.
             mGLSurfaceView.setEGLContextClientVersion(2);
-            mGLSurfaceView.setRenderer(new GLES20TriangleRenderer(this));
+            mRenderer = new GLES20TriangleRenderer(this);
+            mGLSurfaceView.setRenderer(mRenderer);
         } else {
             throw new IllegalStateException("Can't find OGL ES2.0 context");
         }
@@ -84,7 +87,17 @@
         mGLSurfaceView.onPause();
     }
 
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        Log.i("motion", event.toString());
+        if (event.getActionMasked() ==  MotionEvent.ACTION_DOWN) {
+            mRenderer.toggleDepthTest();
+        }
+        return true;
+    }
+
     private GLSurfaceView mGLSurfaceView;
+    private GLES20TriangleRenderer mRenderer;
 
     /*
      * Copyright (C) 2009 The Android Open Source Project Licensed under the
@@ -99,7 +112,9 @@
      */
 
     class GLES20TriangleRenderer implements GLSurfaceView.Renderer {
-
+        private final static int REPEAT_RECTANGLES = 10;
+        private boolean mDepthTestEnabled = true;
+        private final static int FRAME_REPEAT_TIMES = 1;
         public GLES20TriangleRenderer(Context context) {
             mContext = context;
             mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length
@@ -107,39 +122,60 @@
             mTriangleVertices.put(mTriangleVerticesData).position(0);
         }
 
+
+        public void toggleDepthTest() {
+            mDepthTestEnabled = !mDepthTestEnabled;
+            Log.v(TAG, "mDepthTestEnabled is " + mDepthTestEnabled);
+        }
+
         public void onDrawFrame(GL10 glUnused) {
-            // Ignore the passed-in GL10 interface, and use the GLES20
-            // class's static methods instead.
-            GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
-            GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
-            GLES20.glUseProgram(mProgram);
-            checkGlError("glUseProgram");
+            for (int j = 0 ; j < FRAME_REPEAT_TIMES; j ++) {
+                // Ignore the passed-in GL10 interface, and use the GLES20
+                // class's static methods instead.
+                GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+                if (mDepthTestEnabled) {
+                    GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
+                } else {
+                    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+                }
+                GLES20.glUseProgram(mProgram);
+                if (mDepthTestEnabled) {
+                    GLES20.glEnable(GLES20.GL_DEPTH_TEST);
+                } else {
+                    GLES20.glDisable(GLES20.GL_DEPTH_TEST);
+                }
+                checkGlError("glUseProgram");
 
-            GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
-            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
+                GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
 
-            mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
-            GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,
-                    TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
-            checkGlError("glVertexAttribPointer maPosition");
-            mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
-            GLES20.glEnableVertexAttribArray(maPositionHandle);
-            checkGlError("glEnableVertexAttribArray maPositionHandle");
-            GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false,
-                    TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
-            checkGlError("glVertexAttribPointer maTextureHandle");
-            GLES20.glEnableVertexAttribArray(maTextureHandle);
-            checkGlError("glEnableVertexAttribArray maTextureHandle");
+                mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
+                GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,
+                        TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
+                checkGlError("glVertexAttribPointer maPosition");
+                mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
+                GLES20.glEnableVertexAttribArray(maPositionHandle);
+                checkGlError("glEnableVertexAttribArray maPositionHandle");
+                GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false,
+                        TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
+                checkGlError("glVertexAttribPointer maTextureHandle");
+                GLES20.glEnableVertexAttribArray(maTextureHandle);
+                checkGlError("glEnableVertexAttribArray maTextureHandle");
 
-            long time = SystemClock.uptimeMillis() % 4000L;
-            float angle = 0.090f * ((int) time);
-            Matrix.setRotateM(mMMatrix, 0, angle, 0, 0, 1.0f);
-            Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
-            Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
+                for (int i = 0 ; i < REPEAT_RECTANGLES; i ++) {
+                    float step = ((float)i) / REPEAT_RECTANGLES;
+                    Matrix.setIdentityM(mMMatrix, 0);
+                    Matrix.translateM(mMMatrix, 0, 0, step, step / 2);
+                    Matrix.scaleM(mMMatrix, 0, 2.0f, 1.0f, 1.0f);
+                    Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
+                    Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
 
-            GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
-            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
-            checkGlError("glDrawArrays");
+                    GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
+                    GLES20.glUniform4f(muOverlayHandle, step , step, step , step);
+                    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+                    checkGlError("glDrawArrays");
+                }
+            }
         }
 
         public void onSurfaceChanged(GL10 glUnused, int width, int height) {
@@ -174,6 +210,12 @@
                 throw new RuntimeException("Could not get attrib location for uMVPMatrix");
             }
 
+            muOverlayHandle = GLES20.glGetUniformLocation(mProgram, "uOverlay");
+            checkGlError("glGetUniformLocation uOverlay");
+            if (muOverlayHandle == -1) {
+                throw new RuntimeException("Could not get attrib location for muOverlayHandle");
+            }
+
             /*
              * Create our texture. This has to be done each time the surface is
              * created.
@@ -213,6 +255,10 @@
             bitmap.recycle();
 
             Matrix.setLookAtM(mVMatrix, 0, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
+
+            EGLDisplay display = EGL14.eglGetCurrentDisplay();
+            EGL14.eglSwapInterval(display, 0);
+
         }
 
         private int loadShader(int shaderType, String source) {
@@ -276,9 +322,10 @@
         private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
         private final float[] mTriangleVerticesData = {
                                 // X, Y, Z, U, V
-                -1.0f, -0.5f, 0, -0.5f, 0.0f,
-                1.0f, -0.5f, 0, 1.5f, -0.0f,
-                0.0f, 1.11803399f, 0, 0.5f, 1.61803399f };
+                -1.0f, -1.0f, 0, 0.0f, 0.0f,
+                -1.0f, 1.0f, 0, 0.0f, 1.0f,
+                1.0f, -1.0f, 0, 1.0f, 0.0f,
+                1.0f, 1.0f, 0, 1.0f, 1.0f, };
 
         private FloatBuffer mTriangleVertices;
 
@@ -296,8 +343,9 @@
                 "precision mediump float;\n" +
                         "varying vec2 vTextureCoord;\n" +
                         "uniform sampler2D sTexture;\n" +
+                        "uniform vec4 uOverlay;\n" +
                         "void main() {\n" +
-                        "  gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
+                        "  gl_FragColor = texture2D(sTexture, vTextureCoord) * uOverlay;\n" +
                         "}\n";
 
         private float[] mMVPMatrix = new float[16];
@@ -310,6 +358,7 @@
         private int muMVPMatrixHandle;
         private int maPositionHandle;
         private int maTextureHandle;
+        private int muOverlayHandle;
 
         private Context mContext;
         private static final String TAG = "GLES20TriangleRenderer";
diff --git a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
index 33813d1..88ebd1f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
@@ -28,6 +28,8 @@
 
 import com.ibm.icu.lang.UScript;
 import com.ibm.icu.lang.UScriptRun;
+import com.ibm.icu.text.Bidi;
+import com.ibm.icu.text.BidiRun;
 
 import android.graphics.Paint_Delegate.FontInfo;
 
@@ -38,7 +40,7 @@
 @SuppressWarnings("deprecation")
 public class BidiRenderer {
 
-    /*package*/ static class ScriptRun {
+    private static class ScriptRun {
         int start;
         int limit;
         boolean isRtl;
@@ -66,7 +68,7 @@
      * @param paint The Paint to use to get the fonts. Should not be null.
      * @param text Unidirectional text. Should not be null.
      */
-    /*package*/ BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) {
+    public BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) {
         assert (paint != null);
         mGraphics = graphics;
         mPaint = paint;
@@ -75,13 +77,45 @@
         for (FontInfo fontInfo : paint.getFonts()) {
             mFonts.add(fontInfo.mFont);
         }
+        mBounds = new RectF();
+    }
+
+    /**
+     *
+     * @param x The x-coordinate of the left edge of where the text should be drawn on the given
+     *            graphics.
+     * @param y The y-coordinate at which to draw the text on the given mGraphics.
+     *
+     */
+    public BidiRenderer setRenderLocation(float x, float y) {
+        mBounds = new RectF(x, y, x, y);
+        mBaseline = y;
+        return this;
+    }
+
+    /**
+     * Perform Bidi Analysis on the text and then render it.
+     * <p/>
+     * To skip the analysis and render unidirectional text, see {@link
+     * #renderText(int, int, boolean, float[], int, boolean)}
+     */
+    public RectF renderText(int start, int limit, int bidiFlags, float[] advances,
+            int advancesIndex, boolean draw) {
+        Bidi bidi = new Bidi(mText, start, null, 0, limit - start, getIcuFlags(bidiFlags));
+        for (int i = 0; i < bidi.countRuns(); i++) {
+            BidiRun visualRun = bidi.getVisualRun(i);
+            boolean isRtl = visualRun.getDirection() == Bidi.RTL;
+            renderText(visualRun.getStart(), visualRun.getLimit(), isRtl, advances,
+                    advancesIndex, draw);
+        }
+        return mBounds;
     }
 
     /**
      * Render unidirectional text.
-     *
+     * <p/>
      * This method can also be used to measure the width of the text without actually drawing it.
-     *
+     * <p/>
      * @param start index of the first character
      * @param limit index of the first character that should not be rendered.
      * @param isRtl is the text right-to-left
@@ -90,17 +124,12 @@
      * @param advancesIndex index into advances from where the advances need to be filled.
      * @param draw If true and {@code graphics} is not null, draw the rendered text on the graphics
      *            at the given co-ordinates
-     * @param x The x-coordinate of the left edge of where the text should be drawn on the given
-     *            graphics.
-     * @param y The y-coordinate at which to draw the text on the given mGraphics.
      * @return A rectangle specifying the bounds of the text drawn.
      */
-    /* package */ RectF renderText(int start, int limit, boolean isRtl, float[] advances,
-            int advancesIndex, boolean draw, float x, float y) {
+    public RectF renderText(int start, int limit, boolean isRtl, float[] advances,
+            int advancesIndex, boolean draw) {
         // We break the text into scripts and then select font based on it and then render each of
         // the script runs.
-        mBounds = new RectF(x, y, x, y);
-        mBaseline = y;
         for (ScriptRun run : getScriptRuns(mText, start, limit, isRtl, mFonts)) {
             int flag = Font.LAYOUT_NO_LIMIT_CONTEXT | Font.LAYOUT_NO_START_CONTEXT;
             flag |= isRtl ? Font.LAYOUT_RIGHT_TO_LEFT : Font.LAYOUT_LEFT_TO_RIGHT;
@@ -244,4 +273,22 @@
         }
         run.font = fonts.get(0);
     }
+
+    private static int getIcuFlags(int bidiFlag) {
+        switch (bidiFlag) {
+            case Paint.BIDI_LTR:
+            case Paint.BIDI_FORCE_LTR:
+                return Bidi.DIRECTION_LEFT_TO_RIGHT;
+            case Paint.BIDI_RTL:
+            case Paint.BIDI_FORCE_RTL:
+                return Bidi.DIRECTION_RIGHT_TO_LEFT;
+            case Paint.BIDI_DEFAULT_LTR:
+                return Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT;
+            case Paint.BIDI_DEFAULT_RTL:
+                return Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT;
+            default:
+                assert false;
+                return Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT;
+        }
+    }
 }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 7016136..bd88ae2 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -315,7 +315,7 @@
 
     @LayoutlibDelegate
     /*package*/ static void nativeReconfigure(long nativeBitmap, int width, int height,
-            int config, int allocSize) {
+            int config, int allocSize, boolean isPremultiplied) {
         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
                 "Bitmap.reconfigure() is not supported", null /*data*/);
     }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 2ee06fc..7c8ef70 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -55,16 +55,19 @@
     private static final DelegateManager<Canvas_Delegate> sManager =
             new DelegateManager<Canvas_Delegate>(Canvas_Delegate.class);
 
+
     // ---- delegate helper data ----
 
     private final static boolean[] sBoolOut = new boolean[1];
 
+
     // ---- delegate data ----
     private Bitmap_Delegate mBitmap;
     private GcSnapshot mSnapshot;
 
     private DrawFilter_Delegate mDrawFilter = null;
 
+
     // ---- Public Helper methods ----
 
     /**
@@ -100,206 +103,6 @@
     // ---- native methods ----
 
     @LayoutlibDelegate
-    /*package*/ static boolean isOpaque(Canvas thisCanvas) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
-        if (canvasDelegate == null) {
-            return false;
-        }
-
-        return canvasDelegate.mBitmap.getConfig() == Config.RGB_565;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int getWidth(Canvas thisCanvas) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
-        if (canvasDelegate == null) {
-            return 0;
-        }
-
-        return canvasDelegate.mBitmap.getImage().getWidth();
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int getHeight(Canvas thisCanvas) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
-        if (canvasDelegate == null) {
-            return 0;
-        }
-
-        return canvasDelegate.mBitmap.getImage().getHeight();
-    }
-
-    @LayoutlibDelegate
-   /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        canvasDelegate.getSnapshot().translate(dx, dy);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void rotate(Canvas thisCanvas, float degrees) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees));
-    }
-
-    @LayoutlibDelegate
-   /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        canvasDelegate.getSnapshot().scale(sx, sy);
-    }
-
-    @LayoutlibDelegate
-   /*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        // get the current top graphics2D object.
-        GcSnapshot g = canvasDelegate.getSnapshot();
-
-        // get its current matrix
-        AffineTransform currentTx = g.getTransform();
-        // get the AffineTransform for the given skew.
-        float[] mtx = Matrix_Delegate.getSkew(kx, ky);
-        AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx);
-
-        // combine them so that the given matrix is applied after.
-        currentTx.preConcatenate(matrixTx);
-
-        // give it to the graphics2D as a new matrix replacing all previous transform
-        g.setTransform(currentTx);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) {
-        return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) {
-        return clipRect(thisCanvas, (float) rect.left, (float) rect.top,
-                (float) rect.right, (float) rect.bottom);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
-            float bottom) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
-        if (canvasDelegate == null) {
-            return false;
-        }
-
-        return canvasDelegate.clipRect(left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right,
-            int bottom) {
-
-        return clipRect(thisCanvas, (float) left, (float) top, (float) right, (float) bottom);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int save(Canvas thisCanvas) {
-        return save(thisCanvas, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int save(Canvas thisCanvas, int saveFlags) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
-        if (canvasDelegate == null) {
-            return 0;
-        }
-
-        return canvasDelegate.save(saveFlags);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void restore(Canvas thisCanvas) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        canvasDelegate.restore();
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int getSaveCount(Canvas thisCanvas) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
-        if (canvasDelegate == null) {
-            return 0;
-        }
-
-        return canvasDelegate.getSnapshot().size();
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvasWrapper());
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        canvasDelegate.restoreTo(saveCount);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count,
-            Paint paint) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawPoint is not supported.", null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void drawPoint(Canvas thisCanvas, float x, float y, Paint paint) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawPoint is not supported.", null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void drawLines(Canvas thisCanvas,
-            final float[] pts, final int offset, final int count,
-            Paint paint) {
-        draw(thisCanvas.getNativeCanvasWrapper(), paint.mNativePaint, false /*compositeOnly*/,
-                false /*forceSrcMode*/, new GcSnapshot.Drawable() {
-                    @Override
-                    public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
-                        for (int i = 0 ; i < count ; i += 4) {
-                            graphics.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
-                                    (int)pts[i + offset + 2], (int)pts[i + offset + 3]);
-                        }
-                    }
-                });
-    }
-
-    @LayoutlibDelegate
     /*package*/ static void freeCaches() {
         // nothing to be done here.
     }
@@ -328,36 +131,73 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void copyNativeCanvasState(long srcCanvas, long dstCanvas) {
+    /*package*/ static long initCanvas(long nativeCanvas) {
         // get the delegate from the native int.
-        Canvas_Delegate srcCanvasDelegate = sManager.getDelegate(srcCanvas);
-        if (srcCanvasDelegate == null) {
-            return;
+        Canvas_Delegate nativeCanvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (nativeCanvasDelegate == null) {
+            return 0;
         }
 
-        // get the delegate from the native int.
-        Canvas_Delegate dstCanvasDelegate = sManager.getDelegate(dstCanvas);
-        if (dstCanvasDelegate == null) {
-            return;
-        }
+        Canvas_Delegate newDelegate = new Canvas_Delegate();
+
         // TODO: actually copy the canvas state.
+        return sManager.addNewDelegate(newDelegate);
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_saveLayer(long nativeCanvas, RectF bounds,
-                                               long paint, int layerFlags) {
+    /*package*/
+    static void native_setBitmap(long canvas, long bitmap, boolean copyState) {
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
+        Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
+        if (canvasDelegate == null || bitmapDelegate==null) {
+            return;
+        }
+        canvasDelegate.mBitmap = bitmapDelegate;
+        canvasDelegate.mSnapshot = GcSnapshot.createDefaultSnapshot(bitmapDelegate);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean native_isOpaque(long nativeCanvas) {
+        // get the delegate from the native int.
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
+            return false;
+        }
+
+        return canvasDelegate.mBitmap.getConfig() == Config.RGB_565;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static int native_getWidth(long nativeCanvas) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
             return 0;
         }
 
-        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
-        if (paintDelegate == null) {
+        return canvasDelegate.mBitmap.getImage().getWidth();
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static int native_getHeight(long nativeCanvas) {
+        // get the delegate from the native int.
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
             return 0;
         }
 
-        return canvasDelegate.saveLayer(bounds, paintDelegate, layerFlags);
+        return canvasDelegate.mBitmap.getImage().getHeight();
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static int native_save(long nativeCanvas, int saveFlags) {
+        // get the delegate from the native int.
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
+            return 0;
+        }
+
+        return canvasDelegate.save(saveFlags);
     }
 
     @LayoutlibDelegate
@@ -380,19 +220,6 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_saveLayerAlpha(long nativeCanvas,
-                                                    RectF bounds, int alpha,
-                                                    int layerFlags) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return 0;
-        }
-
-        return canvasDelegate.saveLayerAlpha(bounds, alpha, layerFlags);
-    }
-
-    @LayoutlibDelegate
     /*package*/ static int native_saveLayerAlpha(long nativeCanvas, float l,
                                                     float t, float r, float b,
                                                     int alpha, int layerFlags) {
@@ -405,6 +232,95 @@
         return canvasDelegate.saveLayerAlpha(new RectF(l, t, r, b), alpha, layerFlags);
     }
 
+    @LayoutlibDelegate
+    /*package*/ static void native_restore(long nativeCanvas) {
+        // get the delegate from the native int.
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
+            return;
+        }
+
+        canvasDelegate.restore();
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void native_restoreToCount(long nativeCanvas, int saveCount) {
+        // get the delegate from the native int.
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
+            return;
+        }
+
+        canvasDelegate.restoreTo(saveCount);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static int native_getSaveCount(long nativeCanvas) {
+        // get the delegate from the native int.
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
+            return 0;
+        }
+
+        return canvasDelegate.getSnapshot().size();
+    }
+
+    @LayoutlibDelegate
+   /*package*/ static void native_translate(long nativeCanvas, float dx, float dy) {
+        // get the delegate from the native int.
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
+            return;
+        }
+
+        canvasDelegate.getSnapshot().translate(dx, dy);
+    }
+
+    @LayoutlibDelegate
+       /*package*/ static void native_scale(long nativeCanvas, float sx, float sy) {
+            // get the delegate from the native int.
+            Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+            if (canvasDelegate == null) {
+                return;
+            }
+
+            canvasDelegate.getSnapshot().scale(sx, sy);
+        }
+
+    @LayoutlibDelegate
+    /*package*/ static void native_rotate(long nativeCanvas, float degrees) {
+        // get the delegate from the native int.
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
+            return;
+        }
+
+        canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees));
+    }
+
+    @LayoutlibDelegate
+   /*package*/ static void native_skew(long nativeCanvas, float kx, float ky) {
+        // get the delegate from the native int.
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
+            return;
+        }
+
+        // get the current top graphics2D object.
+        GcSnapshot g = canvasDelegate.getSnapshot();
+
+        // get its current matrix
+        AffineTransform currentTx = g.getTransform();
+        // get the AffineTransform for the given skew.
+        float[] mtx = Matrix_Delegate.getSkew(kx, ky);
+        AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx);
+
+        // combine them so that the given matrix is applied after.
+        currentTx.preConcatenate(matrixTx);
+
+        // give it to the graphics2D as a new matrix replacing all previous transform
+        g.setTransform(currentTx);
+    }
 
     @LayoutlibDelegate
     /*package*/ static void native_concat(long nCanvas, long nMatrix) {
@@ -469,7 +385,6 @@
                                                   float left, float top,
                                                   float right, float bottom,
                                                   int regionOp) {
-
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
         if (canvasDelegate == null) {
@@ -568,15 +483,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_quickReject(long nativeCanvas,
-                                                     RectF rect) {
-        // FIXME properly implement quickReject
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean native_quickReject(long nativeCanvas,
-                                                     long path) {
+    /*package*/ static boolean native_quickReject(long nativeCanvas, long path) {
         // FIXME properly implement quickReject
         return false;
     }
@@ -645,10 +552,25 @@
     }
 
     @LayoutlibDelegate
+    /*package*/ static void native_drawPoint(long nativeCanvas, float x, float y,
+            long nativePaint) {
+        // FIXME
+        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+                "Canvas.drawPoint is not supported.", null, null /*data*/);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void native_drawPoints(long nativeCanvas, float[] pts, int offset, int count,
+            long nativePaint) {
+        // FIXME
+        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+                "Canvas.drawPoint is not supported.", null, null /*data*/);
+    }
+
+    @LayoutlibDelegate
     /*package*/ static void native_drawLine(long nativeCanvas,
             final float startX, final float startY, final float stopX, final float stopY,
             long paint) {
-
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
                     @Override
@@ -659,8 +581,19 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawRect(long nativeCanvas, RectF rect, long paint) {
-        native_drawRect(nativeCanvas, rect.left, rect.top, rect.right, rect.bottom, paint);
+    /*package*/ static void native_drawLines(long nativeCanvas,
+            final float[] pts, final int offset, final int count,
+            long nativePaint) {
+        draw(nativeCanvas, nativePaint, false /*compositeOnly*/,
+                false /*forceSrcMode*/, new GcSnapshot.Drawable() {
+                    @Override
+                    public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+                        for (int i = 0; i < count; i += 4) {
+                            graphics.drawLine((int) pts[i + offset], (int) pts[i + offset + 1],
+                                    (int) pts[i + offset + 2], (int) pts[i + offset + 3]);
+                        }
+                    }
+                });
     }
 
     @LayoutlibDelegate
@@ -690,8 +623,9 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawOval(long nativeCanvas, final RectF oval, long paint) {
-        if (oval.right > oval.left && oval.bottom > oval.top) {
+    /*package*/ static void native_drawOval(long nativeCanvas, final float left,
+            final float top, final float right, final float bottom, long paint) {
+        if (right > left && bottom > top) {
             draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                     new GcSnapshot.Drawable() {
                         @Override
@@ -701,14 +635,14 @@
                             // draw
                             if (style == Paint.Style.FILL.nativeInt ||
                                     style == Paint.Style.FILL_AND_STROKE.nativeInt) {
-                                graphics.fillOval((int)oval.left, (int)oval.top,
-                                        (int)oval.width(), (int)oval.height());
+                                graphics.fillOval((int)left, (int)top,
+                                        (int)(right - left), (int)(bottom - top));
                             }
 
                             if (style == Paint.Style.STROKE.nativeInt ||
                                     style == Paint.Style.FILL_AND_STROKE.nativeInt) {
-                                graphics.drawOval((int)oval.left, (int)oval.top,
-                                        (int)oval.width(), (int)oval.height());
+                                graphics.drawOval((int)left, (int)top,
+                                        (int)(right - left), (int)(bottom - top));
                             }
                         }
             });
@@ -719,15 +653,16 @@
     /*package*/ static void native_drawCircle(long nativeCanvas,
             float cx, float cy, float radius, long paint) {
         native_drawOval(nativeCanvas,
-                new RectF(cx - radius, cy - radius, cx + radius, cy + radius),
+                cx - radius, cy - radius, cx + radius, cy + radius,
                 paint);
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_drawArc(long nativeCanvas,
-            final RectF oval, final float startAngle, final float sweep,
+            final float left, final float top, final float right, final float bottom,
+            final float startAngle, final float sweep,
             final boolean useCenter, long paint) {
-        if (oval.right > oval.left && oval.bottom > oval.top) {
+        if (right > left && bottom > top) {
             draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                     new GcSnapshot.Drawable() {
                         @Override
@@ -735,7 +670,7 @@
                             int style = paintDelegate.getStyle();
 
                             Arc2D.Float arc = new Arc2D.Float(
-                                    oval.left, oval.top, oval.width(), oval.height(),
+                                    left, top, right - left, bottom - top,
                                     -startAngle, -sweep,
                                     useCenter ? Arc2D.PIE : Arc2D.OPEN);
 
@@ -758,7 +693,6 @@
     /*package*/ static void native_drawRoundRect(long nativeCanvas,
             final float left, final float top, final float right, final float bottom,
             final float rx, final float ry, long paint) {
-
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
                     @Override
@@ -890,7 +824,6 @@
                                                  final float y, int width, int height,
                                                  boolean hasAlpha,
                                                  long nativePaintOrZero) {
-
         // create a temp BufferedImage containing the content.
         final BufferedImage image = new BufferedImage(width, height,
                 hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
@@ -973,41 +906,10 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawText(long nativeCanvas,
-            final char[] text, final int index, final int count,
-            final float startX, final float startY, final int flags, long paint,
-            final long typeface) {
-
-        draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
-                new GcSnapshot.Drawable() {
-            @Override
-            public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
-                // WARNING: the logic in this method is similar to Paint_Delegate.measureText.
-                // Any change to this method should be reflected in Paint.measureText
-
-                // assert that the typeface passed is actually the one stored in paint.
-                assert (typeface == paintDelegate.mNativeTypeface);
-
-
-                // Paint.TextAlign indicates how the text is positioned relative to X.
-                // LEFT is the default and there's nothing to do.
-                float x = startX;
-                int limit = index + count;
-                boolean isRtl = flags == Canvas.DIRECTION_RTL;
-                if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
-                    RectF bounds = paintDelegate.measureText(text, index, count, isRtl);
-                    float m = bounds.right - bounds.left;
-                    if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
-                        x -= m / 2;
-                    } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
-                        x -= m;
-                    }
-                }
-
-                new BidiRenderer(graphics, paintDelegate, text).renderText(
-                        index, limit, isRtl, null, 0, true, x, startY);
-            }
-        });
+    /*package*/ static void native_drawText(long nativeCanvas, char[] text, int index, int count,
+            float startX, float startY, int flags, long paint, long typeface) {
+        drawText(nativeCanvas, text, index, count, startX, startY, flags == Canvas.DIRECTION_RTL,
+                paint, typeface);
     }
 
     @LayoutlibDelegate
@@ -1024,38 +926,19 @@
     @LayoutlibDelegate
     /*package*/ static void native_drawTextRun(long nativeCanvas, String text,
             int start, int end, int contextStart, int contextEnd,
-            float x, float y, int flags, long paint, long typeface) {
+            float x, float y, boolean isRtl, long paint, long typeface) {
         int count = end - start;
         char[] buffer = TemporaryBuffer.obtain(count);
         TextUtils.getChars(text, start, end, buffer, 0);
 
-        native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface);
+        drawText(nativeCanvas, buffer, 0, count, x, y, isRtl, paint, typeface);
     }
 
     @LayoutlibDelegate
     /*package*/ static void native_drawTextRun(long nativeCanvas, char[] text,
             int start, int count, int contextStart, int contextCount,
-            float x, float y, int flags, long paint, long typeface) {
-        native_drawText(nativeCanvas, text, start, count, x, y, flags, paint, typeface);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void native_drawPosText(long nativeCanvas,
-                                                  char[] text, int index,
-                                                  int count, float[] pos,
-                                                  long paint) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawPosText is not supported.", null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void native_drawPosText(long nativeCanvas,
-                                                  String text, float[] pos,
-                                                  long paint) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawPosText is not supported.", null, null /*data*/);
+            float x, float y, boolean isRtl, long paint, long typeface) {
+        drawText(nativeCanvas, text, start, count, x, y, isRtl, paint, typeface);
     }
 
     @LayoutlibDelegate
@@ -1064,7 +947,7 @@
                                                      int count, long path,
                                                      float hOffset,
                                                      float vOffset, int bidiFlags,
-                                                     long paint) {
+                                                     long paint, long typeface) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                 "Canvas.drawTextOnPath is not supported.", null, null /*data*/);
@@ -1075,7 +958,8 @@
                                                      String text, long path,
                                                      float hOffset,
                                                      float vOffset,
-                                                     int flags, long paint) {
+                                                     int bidiFlags, long paint,
+                                                     long typeface) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                 "Canvas.drawTextOnPath is not supported.", null, null /*data*/);
@@ -1095,6 +979,7 @@
         sManager.removeJavaReferenceFor(nativeCanvas);
     }
 
+
     // ---- Private delegate/helper methods ----
 
     /**
@@ -1132,6 +1017,41 @@
         canvasDelegate.mSnapshot.draw(drawable);
     }
 
+    private static void drawText(long nativeCanvas, final char[] text, final int index,
+            final int count, final float startX, final float startY, final boolean isRtl,
+            long paint, final long typeface) {
+
+        draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+                new GcSnapshot.Drawable() {
+            @Override
+            public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+                // WARNING: the logic in this method is similar to Paint_Delegate.measureText.
+                // Any change to this method should be reflected in Paint.measureText
+
+                // assert that the typeface passed is actually the one stored in paint.
+                assert (typeface == paintDelegate.mNativeTypeface);
+
+                // Paint.TextAlign indicates how the text is positioned relative to X.
+                // LEFT is the default and there's nothing to do.
+                float x = startX;
+                int limit = index + count;
+                if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
+                    RectF bounds = paintDelegate.measureText(text, index, count, null, 0,
+                            isRtl);
+                    float m = bounds.right - bounds.left;
+                    if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
+                        x -= m / 2;
+                    } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
+                        x -= m;
+                    }
+                }
+
+                new BidiRenderer(graphics, paintDelegate, text).setRenderLocation(x, startY)
+                        .renderText(index, limit, isRtl, null, 0, true);
+            }
+        });
+    }
+
     private Canvas_Delegate(Bitmap_Delegate bitmap) {
         mSnapshot = GcSnapshot.createDefaultSnapshot(mBitmap = bitmap);
     }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 5adf4ca..24ef189 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -602,7 +602,7 @@
             return 0;
         }
 
-        RectF bounds = delegate.measureText(text, index, count, isRtl(bidiFlags));
+        RectF bounds = delegate.measureText(text, index, count, null, 0, bidiFlags);
         return bounds.right - bounds.left;
     }
 
@@ -618,11 +618,11 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
-            float maxWidth, int bidiFlags, float[] measuredWidth) {
+    /*package*/ static int native_breakText(long nativePaint, long nativeTypeface, char[] text,
+            int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth) {
 
         // get the delegate
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
             return 0;
         }
@@ -641,7 +641,7 @@
             }
 
             // measure from start to end
-            RectF bounds = delegate.measureText(text, start, end - start + 1, isRtl(bidiFlags));
+            RectF bounds = delegate.measureText(text, start, end - start + 1, null, 0, bidiFlags);
             float res = bounds.right - bounds.left;
 
             if (measuredWidth != null) {
@@ -660,10 +660,11 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
+    /*package*/ static int native_breakText(long nativePaint, long nativeTypeface, String text,
+            boolean measureForwards,
             float maxWidth, int bidiFlags, float[] measuredWidth) {
-        return native_breakText(thisPaint, text.toCharArray(), 0, text.length(), maxWidth,
-                bidiFlags, measuredWidth);
+        return native_breakText(nativePaint, nativeTypeface, text.toCharArray(), 0, text.length(),
+                maxWidth, bidiFlags, measuredWidth);
     }
 
     @LayoutlibDelegate
@@ -950,8 +951,25 @@
     @LayoutlibDelegate
     /*package*/ static int native_getTextWidths(long native_object, long native_typeface,
             char[] text, int index, int count, int bidiFlags, float[] widths) {
-        return (int) native_getTextRunAdvances(native_object, native_typeface, text, index, count,
-                index, count, bidiFlags, widths, 0);
+
+        if (widths != null) {
+            for (int i = 0; i< count; i++) {
+                widths[i]=0;
+            }
+        }
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(native_object);
+        if (delegate == null) {
+            return 0;
+        }
+
+        // native_typeface is passed here since Framework's old implementation did not have the
+        // typeface object associated with the Paint. Since, we follow the new framework way,
+        // we store the typeface with the paint and use it directly.
+        assert (native_typeface == delegate.mNativeTypeface);
+
+        RectF bounds = delegate.measureText(text, index, count, widths, 0, bidiFlags);
+        return ((int) (bounds.right - bounds.left));
     }
 
     @LayoutlibDelegate
@@ -971,7 +989,7 @@
     @LayoutlibDelegate
     /*package*/ static float native_getTextRunAdvances(long native_object, long native_typeface,
             char[] text, int index, int count, int contextIndex, int contextCount,
-            int flags, float[] advances, int advancesIndex) {
+            boolean isRtl, float[] advances, int advancesIndex) {
 
         if (advances != null)
             for (int i = advancesIndex; i< advancesIndex+count; i++)
@@ -987,25 +1005,21 @@
         // we store the typeface with the paint and use it directly.
         assert (native_typeface == delegate.mNativeTypeface);
 
-        boolean isRtl = isRtl(flags);
-
-        int limit = index + count;
-        RectF bounds = new BidiRenderer(null, delegate, text).renderText(
-                index, limit, isRtl, advances, advancesIndex, false, 0, 0);
+        RectF bounds = delegate.measureText(text, index, count, advances, advancesIndex, isRtl);
         return bounds.right - bounds.left;
     }
 
     @LayoutlibDelegate
     /*package*/ static float native_getTextRunAdvances(long native_object, long native_typeface,
             String text, int start, int end, int contextStart, int contextEnd,
-            int flags, float[] advances, int advancesIndex) {
+            boolean isRtl, float[] advances, int advancesIndex) {
         // FIXME: support contextStart and contextEnd
         int count = end - start;
         char[] buffer = TemporaryBuffer.obtain(count);
         TextUtils.getChars(text, start, end, buffer, 0);
 
         return native_getTextRunAdvances(native_object, native_typeface, buffer, 0, count,
-                contextStart, contextEnd - contextStart, flags, advances, advancesIndex);
+                contextStart, contextEnd - contextStart, isRtl, advances, advancesIndex);
     }
 
     @LayoutlibDelegate
@@ -1062,7 +1076,7 @@
         // assert that the typeface passed is actually the one that we had stored.
         assert (native_typeface == delegate.mNativeTypeface);
 
-        delegate.measureText(text, index, count, isRtl(bidiFlags)).roundOut(bounds);
+        delegate.measureText(text, index, count, null, 0, bidiFlags).roundOut(bounds);
     }
 
     @LayoutlibDelegate
@@ -1158,9 +1172,16 @@
         }
     }
 
-    /*package*/ RectF measureText(char[] text, int index, int count, boolean isRtl) {
-        return new BidiRenderer(null, this, text).renderText(
-                index, index + count, isRtl, null, 0, false, 0, 0);
+    /*package*/ RectF measureText(char[] text, int index, int count, float[] advances,
+            int advancesIndex, int bidiFlags) {
+        return new BidiRenderer(null, this, text)
+                .renderText(index, index + count, bidiFlags, advances, advancesIndex, false);
+    }
+
+    /*package*/ RectF measureText(char[] text, int index, int count, float[] advances,
+            int advancesIndex, boolean isRtl) {
+        return new BidiRenderer(null, this, text)
+                .renderText(index, index + count, isRtl, advances, advancesIndex, false);
     }
 
     private float getFontMetrics(FontMetrics metrics) {
@@ -1198,15 +1219,4 @@
             delegate.mFlags &= ~flagMask;
         }
     }
-
-    private static boolean isRtl(int flag) {
-        switch(flag) {
-        case Paint.BIDI_RTL:
-        case Paint.BIDI_FORCE_RTL:
-        case Paint.BIDI_DEFAULT_RTL:
-            return true;
-        default:
-            return false;
-        }
-    }
 }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 0ec7115..7153a90 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -297,14 +297,15 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_arcTo(long nPath, RectF oval,
+    /*package*/ static void native_arcTo(long nPath, float left, float top, float right,
+            float bottom,
                     float startAngle, float sweepAngle, boolean forceMoveTo) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
         }
 
-        pathDelegate.arcTo(oval, startAngle, sweepAngle, forceMoveTo);
+        pathDelegate.arcTo(left, top, right, bottom, startAngle, sweepAngle, forceMoveTo);
     }
 
     @LayoutlibDelegate
@@ -353,8 +354,8 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addArc(long nPath, RectF oval,
-            float startAngle, float sweepAngle) {
+    /*package*/ static void native_addArc(long nPath, float left, float top, float right,
+            float bottom, float startAngle, float sweepAngle) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
@@ -362,13 +363,13 @@
 
         // because x/y is the center of the circle, need to offset this by the radius
         pathDelegate.mPath.append(new Arc2D.Float(
-                oval.left, oval.top, oval.width(), oval.height(),
+                left, top, right - left, bottom - top,
                 -startAngle, -sweepAngle, Arc2D.OPEN), false);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addRoundRect(
-            long nPath, RectF rect, float rx, float ry, int dir) {
+    /*package*/ static void native_addRoundRect(long nPath, float left, float top, float right,
+            float bottom, float rx, float ry, int dir) {
 
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
@@ -376,14 +377,15 @@
         }
 
         pathDelegate.mPath.append(new RoundRectangle2D.Float(
-                rect.left, rect.top, rect.width(), rect.height(), rx * 2, ry * 2), false);
+                left, top, right - left, bottom - top, rx * 2, ry * 2), false);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addRoundRect(long nPath, RectF rect, float[] radii, int dir) {
+    /*package*/ static void native_addRoundRect(long nPath, float left, float top, float right,
+            float bottom, float[] radii, int dir) {
         // Java2D doesn't support different rounded corners in each corner, so just use the
         // first value.
-        native_addRoundRect(nPath, rect, radii[0], radii[1], dir);
+        native_addRoundRect(nPath, left, top, right, bottom, radii[0], radii[1], dir);
 
         // there can be a case where this API is used but with similar values for all corners, so
         // in that case we don't warn.
@@ -710,14 +712,19 @@
      * start of the arc. However, if the path is empty, then we call moveTo()
      * with the first point of the arc. The sweep angle is tread mod 360.
      *
-     * @param oval        The bounds of oval defining shape and size of the arc
+     * @param left        The left of oval defining shape and size of the arc
+     * @param top         The top of oval defining shape and size of the arc
+     * @param right       The right of oval defining shape and size of the arc
+     * @param bottom      The bottom of oval defining shape and size of the arc
      * @param startAngle  Starting angle (in degrees) where the arc begins
      * @param sweepAngle  Sweep angle (in degrees) measured clockwise, treated
      *                    mod 360.
      * @param forceMoveTo If true, always begin a new contour with the arc
      */
-    private void arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) {
-        Arc2D arc = new Arc2D.Float(oval.left, oval.top, oval.width(), oval.height(), -startAngle,
+    private void arcTo(float left, float top, float right, float bottom, float startAngle,
+            float sweepAngle,
+            boolean forceMoveTo) {
+        Arc2D arc = new Arc2D.Float(left, top, right - left, bottom - top, -startAngle,
                 -sweepAngle, Arc2D.OPEN);
         mPath.append(arc, true /*connect*/);
 
diff --git a/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java b/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java
index 973fa0e..6247dae 100644
--- a/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java
@@ -37,14 +37,17 @@
 
         switch (dir) {
         case 0: // Layout.DIR_REQUEST_LTR
-        case 1: // Layout.DIR_REQUEST_RTL
-            break;  // No change.
-        case -1:
-            dir = Bidi.LEVEL_DEFAULT_LTR;
+            dir = Bidi.LTR;
             break;
-        case -2:
+        case 1: // Layout.DIR_REQUEST_RTL
+            dir = Bidi.RTL;
+            break;
+        case -1: // Layout.DIR_REQUEST_DEFAULT_RTL
             dir = Bidi.LEVEL_DEFAULT_RTL;
             break;
+        case -2: // Layout.DIR_REQUEST_DEFAULT_LTR
+            dir = Bidi.LEVEL_DEFAULT_LTR;
+            break;
         default:
             // Invalid code. Log error, assume LEVEL_DEFAULT_LTR and continue.
             Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Invalid direction flag", null);
diff --git a/tools/layoutlib/bridge/src/dalvik/system/VMRuntime_Delegate.java b/tools/layoutlib/bridge/src/dalvik/system/VMRuntime_Delegate.java
new file mode 100644
index 0000000..36efc3a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/dalvik/system/VMRuntime_Delegate.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 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 dalvik.system;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate used to provide implementation of a select few native methods of {@link VMRuntime}
+ * <p/>
+ * Through the layoutlib_create tool, the original native methods of VMRuntime have been replaced
+ * by calls to methods of the same name in this delegate class.
+ */
+public class VMRuntime_Delegate {
+
+    // Copied from libcore/libdvm/src/main/java/dalvik/system/VMRuntime
+    @LayoutlibDelegate
+    /*package*/ static Object newUnpaddedArray(VMRuntime runtime, Class<?> componentType,
+            int minLength) {
+        // Dalvik has 32bit pointers, the array header is 16bytes plus 4bytes for dlmalloc,
+        // allocations are 8byte aligned so having 4bytes of array data avoids padding.
+        if (!componentType.isPrimitive()) {
+            int size = ((minLength & 1) == 0) ? minLength + 1 : minLength;
+            return java.lang.reflect.Array.newInstance(componentType, size);
+        } else if (componentType == char.class) {
+            int bytes = 20 + (2 * minLength);
+            int alignedUpBytes = (bytes + 7) & -8;
+            int dataBytes = alignedUpBytes - 20;
+            int size = dataBytes / 2;
+            return new char[size];
+        } else if (componentType == int.class) {
+            int size = ((minLength & 1) == 0) ? minLength + 1 : minLength;
+            return new int[size];
+        } else if (componentType == byte.class) {
+            int bytes = 20 + minLength;
+            int alignedUpBytes = (bytes + 7) & -8;
+            int dataBytes = alignedUpBytes - 20;
+            int size = dataBytes;
+            return new byte[size];
+        } else if (componentType == boolean.class) {
+            int bytes = 20 + minLength;
+            int alignedUpBytes = (bytes + 7) & -8;
+            int dataBytes = alignedUpBytes - 20;
+            int size = dataBytes;
+            return new boolean[size];
+        } else if (componentType == short.class) {
+            int bytes = 20 + (2 * minLength);
+            int alignedUpBytes = (bytes + 7) & -8;
+            int dataBytes = alignedUpBytes - 20;
+            int size = dataBytes / 2;
+            return new short[size];
+        } else if (componentType == float.class) {
+            int size = ((minLength & 1) == 0) ? minLength + 1 : minLength;
+            return new float[size];
+        } else if (componentType == long.class) {
+            return new long[minLength];
+        } else if (componentType == double.class) {
+            return new double[minLength];
+        } else {
+            assert componentType == void.class;
+            throw new IllegalArgumentException("Can't allocate an array of void");
+        }
+    }
+
+}
diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
index 19d249b..71947b0 100644
--- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -148,12 +148,12 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static String getISO3CountryNative(String locale) {
+    /*package*/ static String getISO3Country(String locale) {
         return "";
     }
 
     @LayoutlibDelegate
-    /*package*/ static String getISO3LanguageNative(String locale) {
+    /*package*/ static String getISO3Language(String locale) {
         return "";
     }
 
@@ -184,11 +184,6 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static String languageTagForLocale(String locale) {
-        return "";
-    }
-
-    @LayoutlibDelegate
     /*package*/ static boolean initLocaleDataNative(String locale, LocaleData result) {
 
         // Used by Calendar.
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
index 274516c..8b362ec 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
@@ -41,27 +41,29 @@
  */
 public class TestDelegates extends TestCase {
 
+    private List<String> mErrors = new ArrayList<String>();
+
     public void testNativeDelegates() {
 
         final String[] classes = CreateInfo.DELEGATE_CLASS_NATIVES;
-        final int count = classes.length;
-        for (int i = 0 ; i < count ; i++) {
-            loadAndCompareClasses(classes[i], classes[i] + "_Delegate");
+        mErrors.clear();
+        for (String clazz : classes) {
+            loadAndCompareClasses(clazz, clazz + "_Delegate");
         }
+        assertTrue(getErrors(), mErrors.isEmpty());
     }
 
     public void testMethodDelegates() {
         final String[] methods = CreateInfo.DELEGATE_METHODS;
-        final int count = methods.length;
-        for (int i = 0 ; i < count ; i++) {
-            String methodName = methods[i];
-
+        mErrors.clear();
+        for (String methodName : methods) {
             // extract the class name
             String className = methodName.substring(0, methodName.indexOf('#'));
             String targetClassName = className.replace('$', '_') + "_Delegate";
 
             loadAndCompareClasses(className, targetClassName);
         }
+        assertTrue(getErrors(), mErrors.isEmpty());
     }
 
     private void loadAndCompareClasses(String originalClassName, String delegateClassName) {
@@ -73,9 +75,9 @@
 
             compare(originalClass, delegateClass);
         } catch (ClassNotFoundException e) {
-           fail("Failed to load class: " + e.getMessage());
+            mErrors.add("Failed to load class: " + e.getMessage());
         } catch (SecurityException e) {
-            fail("Failed to load class: " + e.getMessage());
+            mErrors.add("Failed to load class: " + e.getMessage());
         }
     }
 
@@ -122,35 +124,39 @@
                         parameters);
 
                 // check the return type of the methods match.
-                assertTrue(
-                        String.format("Delegate method %1$s.%2$s does not match the corresponding " +
-                                "framework method which returns %3$s",
-                                delegateClass.getName(),
-                                getMethodName(delegateMethod),
-                                originalMethod.getReturnType().getName()),
-                        delegateMethod.getReturnType() == originalMethod.getReturnType());
+                if (delegateMethod.getReturnType() != originalMethod.getReturnType()) {
+                    mErrors.add(
+                            String.format("Delegate method %1$s.%2$s does not match the " +
+                                    "corresponding framework method which returns %3$s",
+                            delegateClass.getName(),
+                            getMethodName(delegateMethod),
+                            originalMethod.getReturnType().getName()));
+                }
 
                 // check that the method has the annotation
-                assertNotNull(
-                        String.format(
-                                "Delegate method %1$s for class %2$s does not have the @LayoutlibDelegate annotation",
-                                delegateMethod.getName(),
-                                originalClass.getName()),
-                        delegateMethod.getAnnotation(LayoutlibDelegate.class));
+                if (delegateMethod.getAnnotation(LayoutlibDelegate.class) == null) {
+                    mErrors.add(
+                            String.format("Delegate method %1$s for class %2$s does not have the " +
+                                            "@LayoutlibDelegate annotation",
+                                    delegateMethod.getName(),
+                                    originalClass.getName()));
+                }
 
                 // check that the method is static
-                assertTrue(
-                        String.format(
-                                "Delegate method %1$s for class %2$s is not static",
-                                delegateMethod.getName(),
-                                originalClass.getName()),
-                        (delegateMethod.getModifiers() & Modifier.STATIC) == Modifier.STATIC);
+                if ((delegateMethod.getModifiers() & Modifier.STATIC) != Modifier.STATIC) {
+                    mErrors.add(
+                            String.format(
+                                    "Delegate method %1$s for class %2$s is not static",
+                                    delegateMethod.getName(),
+                                    originalClass.getName())
+                    );
+                }
 
                 // add the method as checked.
                 checkedDelegateMethods.add(delegateMethod);
             } catch (NoSuchMethodException e) {
                 String name = getMethodName(originalMethod, parameters);
-                fail(String.format("Missing %1$s.%2$s", delegateClass.getName(), name));
+                mErrors.add(String.format("Missing %1$s.%2$s", delegateClass.getName(), name));
             }
         }
 
@@ -167,12 +173,12 @@
                 continue;
             }
 
-            assertTrue(
-                    String.format(
-                            "Delegate method %1$s.%2$s is not used anymore and must be removed",
-                            delegateClass.getName(),
-                            getMethodName(delegateMethod)),
-                    checkedDelegateMethods.contains(delegateMethod));
+            if (!checkedDelegateMethods.contains(delegateMethod)) {
+                mErrors.add(String.format(
+                        "Delegate method %1$s.%2$s is not used anymore and must be removed",
+                        delegateClass.getName(),
+                        getMethodName(delegateMethod)));
+            }
         }
 
     }
@@ -203,4 +209,12 @@
 
         return sb.toString();
     }
+
+    private String getErrors() {
+        StringBuilder s = new StringBuilder();
+        for (String error : mErrors) {
+            s.append(error).append('\n');
+        }
+        return s.toString();
+    }
 }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 1f7a28e..552fb6c 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -152,6 +152,7 @@
         "com.android.internal.util.XmlUtils#convertValueToInt",
         "com.android.internal.textservice.ITextServicesManager$Stub#asInterface",
         "android.os.SystemProperties#native_get",
+        "dalvik.system.VMRuntime#newUnpaddedArray"
     };
 
     /**
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
index e7e6767..ddca85e 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
@@ -221,12 +221,22 @@
             return key;
         }
 
-        private Object getListener(int key, boolean force) {
-            Log.d(TAG, "getListener() key=" + key + " force=" + force);
+        private Object peekListener(int key) {
+            Log.d(TAG, "peekListener() key=" + key);
             if (key == INVALID_LISTENER_KEY)
                 return null;
             synchronized (mListenerMapLock) {
-                if (!force) {
+                return mListenerMap.get(key);
+            }
+        }
+
+
+        private Object getListener(int key, boolean forceRemove) {
+            Log.d(TAG, "getListener() key=" + key + " force=" + forceRemove);
+            if (key == INVALID_LISTENER_KEY)
+                return null;
+            synchronized (mListenerMapLock) {
+                if (!forceRemove) {
                     int count = mListenerMapCount.get(key);
                     Log.d(TAG, "count=" + count);
                     mListenerMapCount.put(key, --count);
@@ -322,7 +332,7 @@
                         break;
 
                     case START_OSU_BROWSER:
-                        listener = getListener(message.arg2, true);
+                        listener = peekListener(message.arg2);
                         if (listener != null) {
                             ParcelableString str = (ParcelableString) message.obj;
                             if (str == null || str.string == null)