Merge "Adding user consent extras to DevicePolicyManager."
diff --git a/Android.mk b/Android.mk
index 2f3a990..642d8b9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -217,14 +217,6 @@
 	core/java/android/service/wallpaper/IWallpaperConnection.aidl \
 	core/java/android/service/wallpaper/IWallpaperEngine.aidl \
 	core/java/android/service/wallpaper/IWallpaperService.aidl \
-	core/java/android/tv/ITvInputClient.aidl \
-	core/java/android/tv/ITvInputHardware.aidl \
-	core/java/android/tv/ITvInputHardwareCallback.aidl \
-	core/java/android/tv/ITvInputManager.aidl \
-	core/java/android/tv/ITvInputService.aidl \
-	core/java/android/tv/ITvInputServiceCallback.aidl \
-	core/java/android/tv/ITvInputSession.aidl \
-	core/java/android/tv/ITvInputSessionCallback.aidl \
 	core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl\
 	core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl\
 	core/java/android/view/accessibility/IAccessibilityManager.aidl \
@@ -322,6 +314,14 @@
         media/java/android/media/session/ISession.aidl \
         media/java/android/media/session/ISessionCallback.aidl \
         media/java/android/media/session/ISessionManager.aidl \
+	media/java/android/media/tv/ITvInputClient.aidl \
+	media/java/android/media/tv/ITvInputHardware.aidl \
+	media/java/android/media/tv/ITvInputHardwareCallback.aidl \
+	media/java/android/media/tv/ITvInputManager.aidl \
+	media/java/android/media/tv/ITvInputService.aidl \
+	media/java/android/media/tv/ITvInputServiceCallback.aidl \
+	media/java/android/media/tv/ITvInputSession.aidl \
+	media/java/android/media/tv/ITvInputSessionCallback.aidl \
 	telecomm/java/com/android/internal/telecomm/ICallService.aidl \
 	telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl \
 	telecomm/java/com/android/internal/telecomm/ICallServiceLookupResponse.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 48a20a4..f3bb9b6 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -192,6 +192,7 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/media/java/android/media/)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/app/wearable)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/tv/ITv*)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/api/current.txt b/api/current.txt
index e9bae81..b5849ed 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15979,6 +15979,160 @@
 
 }
 
+package android.media.tv {
+
+  public final class TvContract {
+    method public static final android.net.Uri buildChannelUri(long);
+    method public static final android.net.Uri buildChannelsUriForInput(android.content.ComponentName);
+    method public static final android.net.Uri buildChannelsUriForInput(android.content.ComponentName, boolean);
+    method public static final android.net.Uri buildProgramUri(long);
+    method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri);
+    method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
+    field public static final java.lang.String AUTHORITY = "com.android.tv";
+  }
+
+  public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
+    field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
+  }
+
+  public static final class TvContract.Channels implements android.media.tv.TvContract.BaseTvColumns {
+    field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
+    field public static final java.lang.String COLUMN_DATA = "data";
+    field public static final java.lang.String COLUMN_DESCRIPTION = "description";
+    field public static final java.lang.String COLUMN_DISPLAY_NAME = "display_name";
+    field public static final java.lang.String COLUMN_DISPLAY_NUMBER = "display_number";
+    field public static final java.lang.String COLUMN_LOCKED = "locked";
+    field public static final java.lang.String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
+    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
+    field public static final java.lang.String COLUMN_SERVICE_ID = "service_id";
+    field public static final java.lang.String COLUMN_SERVICE_NAME = "service_name";
+    field public static final java.lang.String COLUMN_SERVICE_TYPE = "service_type";
+    field public static final java.lang.String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
+    field public static final java.lang.String COLUMN_TYPE = "type";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.android.tv.channels";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.com.android.tv.channels";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final int SERVICE_TYPE_OTHER = 0; // 0x0
+    field public static final int SERVICE_TYPE_RADIO = 2; // 0x2
+    field public static final int SERVICE_TYPE_TV = 1; // 0x1
+    field public static final int TYPE_1SEG = 263168; // 0x40400
+    field public static final int TYPE_ATSC_C = 197120; // 0x30200
+    field public static final int TYPE_ATSC_M_H = 197120; // 0x30200
+    field public static final int TYPE_ATSC_T = 196608; // 0x30000
+    field public static final int TYPE_CMMB = 327936; // 0x50100
+    field public static final int TYPE_DTMB = 327680; // 0x50000
+    field public static final int TYPE_DVB_C = 131584; // 0x20200
+    field public static final int TYPE_DVB_C2 = 131585; // 0x20201
+    field public static final int TYPE_DVB_H = 131840; // 0x20300
+    field public static final int TYPE_DVB_S = 131328; // 0x20100
+    field public static final int TYPE_DVB_S2 = 131329; // 0x20101
+    field public static final int TYPE_DVB_SH = 132096; // 0x20400
+    field public static final int TYPE_DVB_T = 131072; // 0x20000
+    field public static final int TYPE_DVB_T2 = 131073; // 0x20001
+    field public static final int TYPE_ISDB_C = 262912; // 0x40300
+    field public static final int TYPE_ISDB_S = 262656; // 0x40200
+    field public static final int TYPE_ISDB_T = 262144; // 0x40000
+    field public static final int TYPE_ISDB_TB = 262400; // 0x40100
+    field public static final int TYPE_OTHER = 0; // 0x0
+    field public static final int TYPE_PASSTHROUGH = 65536; // 0x10000
+    field public static final int TYPE_S_DMB = 393472; // 0x60100
+    field public static final int TYPE_T_DMB = 393216; // 0x60000
+  }
+
+  public static final class TvContract.Programs implements android.media.tv.TvContract.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_DATA = "data";
+    field public static final java.lang.String COLUMN_DESCRIPTION = "description";
+    field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final java.lang.String COLUMN_GENRE = "genre";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.android.tv.programs";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.com.android.tv.programs";
+    field public static final android.net.Uri CONTENT_URI;
+  }
+
+  public final class TvInputInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.ComponentName getComponent();
+    method public java.lang.String getId();
+    method public java.lang.String getPackageName();
+    method public java.lang.String getServiceName();
+    method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
+    method public void writeToParcel(android.os.Parcel, int);
+  }
+
+  public final class TvInputManager {
+    method public void createSession(java.lang.String, android.media.tv.TvInputManager.SessionCallback, android.os.Handler);
+    method public boolean getAvailability(java.lang.String);
+    method public java.util.List<android.media.tv.TvInputInfo> getTvInputList();
+    method public void registerListener(java.lang.String, android.media.tv.TvInputManager.TvInputListener, android.os.Handler);
+    method public void unregisterListener(java.lang.String, android.media.tv.TvInputManager.TvInputListener);
+  }
+
+  public static final class TvInputManager.Session {
+    method public void release();
+    method public void setVolume(float);
+    method public void tune(android.net.Uri);
+  }
+
+  public static abstract class TvInputManager.SessionCallback {
+    ctor public TvInputManager.SessionCallback();
+    method public void onSessionCreated(android.media.tv.TvInputManager.Session);
+    method public void onSessionReleased(android.media.tv.TvInputManager.Session);
+  }
+
+  public static abstract class TvInputManager.TvInputListener {
+    ctor public TvInputManager.TvInputListener();
+    method public void onAvailabilityChanged(java.lang.String, boolean);
+  }
+
+  public abstract class TvInputService extends android.app.Service {
+    ctor public TvInputService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract android.media.tv.TvInputService.TvInputSessionImpl onCreateSession();
+    method public final void setAvailable(boolean);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
+  }
+
+  public abstract class TvInputService.TvInputSessionImpl implements android.view.KeyEvent.Callback {
+    ctor public TvInputService.TvInputSessionImpl();
+    method public android.view.View onCreateOverlayView();
+    method public boolean onGenericMotionEvent(android.view.MotionEvent);
+    method public boolean onKeyDown(int, android.view.KeyEvent);
+    method public boolean onKeyLongPress(int, android.view.KeyEvent);
+    method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
+    method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public abstract void onRelease();
+    method public abstract boolean onSetSurface(android.view.Surface);
+    method public abstract void onSetVolume(float);
+    method public boolean onTouchEvent(android.view.MotionEvent);
+    method public boolean onTrackballEvent(android.view.MotionEvent);
+    method public abstract boolean onTune(android.net.Uri);
+    method public void setOverlayViewEnabled(boolean);
+  }
+
+  public class TvView extends android.view.SurfaceView {
+    ctor public TvView(android.content.Context);
+    ctor public TvView(android.content.Context, android.util.AttributeSet);
+    ctor public TvView(android.content.Context, android.util.AttributeSet, int);
+    method public void bindTvInput(java.lang.String, android.media.tv.TvInputManager.SessionCallback);
+    method public boolean dispatchUnhandledInputEvent(android.view.InputEvent);
+    method public boolean onUnhandledInputEvent(android.view.InputEvent);
+    method public void setOnUnhandledInputEventListener(android.media.tv.TvView.OnUnhandledInputEventListener);
+    method public void unbindTvInput();
+  }
+
+  public static abstract interface TvView.OnUnhandledInputEventListener {
+    method public abstract boolean onUnhandledInputEvent(android.view.InputEvent);
+  }
+
+}
+
 package android.mtp {
 
   public final class MtpConstants {
@@ -24946,81 +25100,6 @@
     field public static final java.lang.String TYPE = "type";
   }
 
-  public final class TvContract {
-    method public static final android.net.Uri buildChannelUri(long);
-    method public static final android.net.Uri buildChannelsUriForInput(android.content.ComponentName);
-    method public static final android.net.Uri buildChannelsUriForInput(android.content.ComponentName, boolean);
-    method public static final android.net.Uri buildProgramUri(long);
-    method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri);
-    method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
-    field public static final java.lang.String AUTHORITY = "com.android.tv";
-  }
-
-  public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
-    field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
-  }
-
-  public static final class TvContract.Channels implements android.provider.TvContract.BaseTvColumns {
-    field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
-    field public static final java.lang.String COLUMN_DATA = "data";
-    field public static final java.lang.String COLUMN_DESCRIPTION = "description";
-    field public static final java.lang.String COLUMN_DISPLAY_NAME = "display_name";
-    field public static final java.lang.String COLUMN_DISPLAY_NUMBER = "display_number";
-    field public static final java.lang.String COLUMN_LOCKED = "locked";
-    field public static final java.lang.String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
-    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SERVICE_ID = "service_id";
-    field public static final java.lang.String COLUMN_SERVICE_NAME = "service_name";
-    field public static final java.lang.String COLUMN_SERVICE_TYPE = "service_type";
-    field public static final java.lang.String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
-    field public static final java.lang.String COLUMN_TYPE = "type";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.android.tv.channels";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.com.android.tv.channels";
-    field public static final android.net.Uri CONTENT_URI;
-    field public static final int SERVICE_TYPE_OTHER = 0; // 0x0
-    field public static final int SERVICE_TYPE_RADIO = 2; // 0x2
-    field public static final int SERVICE_TYPE_TV = 1; // 0x1
-    field public static final int TYPE_1SEG = 263168; // 0x40400
-    field public static final int TYPE_ATSC_C = 197120; // 0x30200
-    field public static final int TYPE_ATSC_M_H = 197120; // 0x30200
-    field public static final int TYPE_ATSC_T = 196608; // 0x30000
-    field public static final int TYPE_CMMB = 327936; // 0x50100
-    field public static final int TYPE_DTMB = 327680; // 0x50000
-    field public static final int TYPE_DVB_C = 131584; // 0x20200
-    field public static final int TYPE_DVB_C2 = 131585; // 0x20201
-    field public static final int TYPE_DVB_H = 131840; // 0x20300
-    field public static final int TYPE_DVB_S = 131328; // 0x20100
-    field public static final int TYPE_DVB_S2 = 131329; // 0x20101
-    field public static final int TYPE_DVB_SH = 132096; // 0x20400
-    field public static final int TYPE_DVB_T = 131072; // 0x20000
-    field public static final int TYPE_DVB_T2 = 131073; // 0x20001
-    field public static final int TYPE_ISDB_C = 262912; // 0x40300
-    field public static final int TYPE_ISDB_S = 262656; // 0x40200
-    field public static final int TYPE_ISDB_T = 262144; // 0x40000
-    field public static final int TYPE_ISDB_TB = 262400; // 0x40100
-    field public static final int TYPE_OTHER = 0; // 0x0
-    field public static final int TYPE_PASSTHROUGH = 65536; // 0x10000
-    field public static final int TYPE_S_DMB = 393472; // 0x60100
-    field public static final int TYPE_T_DMB = 393216; // 0x60000
-  }
-
-  public static final class TvContract.Programs implements android.provider.TvContract.BaseTvColumns {
-    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
-    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
-    field public static final java.lang.String COLUMN_DATA = "data";
-    field public static final java.lang.String COLUMN_DESCRIPTION = "description";
-    field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_GENRE = "genre";
-    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
-    field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
-    field public static final java.lang.String COLUMN_TITLE = "title";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.android.tv.programs";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.com.android.tv.programs";
-    field public static final android.net.Uri CONTENT_URI;
-  }
-
   public class UserDictionary {
     ctor public UserDictionary();
     field public static final java.lang.String AUTHORITY = "user_dictionary";
@@ -30594,85 +30673,6 @@
 
 }
 
-package android.tv {
-
-  public final class TvInputInfo implements android.os.Parcelable {
-    method public int describeContents();
-    method public android.content.ComponentName getComponent();
-    method public java.lang.String getId();
-    method public java.lang.String getPackageName();
-    method public java.lang.String getServiceName();
-    method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
-    method public void writeToParcel(android.os.Parcel, int);
-  }
-
-  public final class TvInputManager {
-    method public void createSession(java.lang.String, android.tv.TvInputManager.SessionCallback, android.os.Handler);
-    method public boolean getAvailability(java.lang.String);
-    method public java.util.List<android.tv.TvInputInfo> getTvInputList();
-    method public void registerListener(java.lang.String, android.tv.TvInputManager.TvInputListener, android.os.Handler);
-    method public void unregisterListener(java.lang.String, android.tv.TvInputManager.TvInputListener);
-  }
-
-  public static final class TvInputManager.Session {
-    method public void release();
-    method public void setVolume(float);
-    method public void tune(android.net.Uri);
-  }
-
-  public static abstract class TvInputManager.SessionCallback {
-    ctor public TvInputManager.SessionCallback();
-    method public void onSessionCreated(android.tv.TvInputManager.Session);
-    method public void onSessionReleased(android.tv.TvInputManager.Session);
-  }
-
-  public static abstract class TvInputManager.TvInputListener {
-    ctor public TvInputManager.TvInputListener();
-    method public void onAvailabilityChanged(java.lang.String, boolean);
-  }
-
-  public abstract class TvInputService extends android.app.Service {
-    ctor public TvInputService();
-    method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract android.tv.TvInputService.TvInputSessionImpl onCreateSession();
-    method public final void setAvailable(boolean);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.tv.TvInputService";
-  }
-
-  public abstract class TvInputService.TvInputSessionImpl implements android.view.KeyEvent.Callback {
-    ctor public TvInputService.TvInputSessionImpl();
-    method public android.view.View onCreateOverlayView();
-    method public boolean onGenericMotionEvent(android.view.MotionEvent);
-    method public boolean onKeyDown(int, android.view.KeyEvent);
-    method public boolean onKeyLongPress(int, android.view.KeyEvent);
-    method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
-    method public boolean onKeyUp(int, android.view.KeyEvent);
-    method public abstract void onRelease();
-    method public abstract boolean onSetSurface(android.view.Surface);
-    method public abstract void onSetVolume(float);
-    method public boolean onTouchEvent(android.view.MotionEvent);
-    method public boolean onTrackballEvent(android.view.MotionEvent);
-    method public abstract boolean onTune(android.net.Uri);
-    method public void setOverlayViewEnabled(boolean);
-  }
-
-  public class TvView extends android.view.SurfaceView {
-    ctor public TvView(android.content.Context);
-    ctor public TvView(android.content.Context, android.util.AttributeSet);
-    ctor public TvView(android.content.Context, android.util.AttributeSet, int);
-    method public void bindTvInput(java.lang.String, android.tv.TvInputManager.SessionCallback);
-    method public boolean dispatchUnhandledInputEvent(android.view.InputEvent);
-    method public boolean onUnhandledInputEvent(android.view.InputEvent);
-    method public void setOnUnhandledInputEventListener(android.tv.TvView.OnUnhandledInputEventListener);
-    method public void unbindTvInput();
-  }
-
-  public static abstract interface TvView.OnUnhandledInputEventListener {
-    method public abstract boolean onUnhandledInputEvent(android.view.InputEvent);
-  }
-
-}
-
 package android.util {
 
   public class AndroidException extends java.lang.Exception {
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index b7c2c22..47047b8 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -39,6 +39,7 @@
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IUserManager;
 import android.os.Process;
@@ -57,7 +58,6 @@
 import java.util.Comparator;
 import java.util.List;
 import java.util.WeakHashMap;
-
 import javax.crypto.SecretKey;
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
@@ -823,6 +823,7 @@
         byte[] tag = null;
         String originatingUriString = null;
         String referrer = null;
+        String abi = null;
 
         while ((opt=nextOption()) != null) {
             if (opt.equals("-l")) {
@@ -893,12 +894,34 @@
                     System.err.println("Error: must supply argument for --referrer");
                     return;
                 }
+            } else if (opt.equals("--abi")) {
+                abi = nextOptionData();
+                if (abi == null) {
+                    System.err.println("Error: must supply argument for --abi");
+                    return;
+                }
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 return;
             }
         }
 
+        if (abi != null) {
+            final String[] supportedAbis = Build.SUPPORTED_ABIS;
+            boolean matched = false;
+            for (String supportedAbi : supportedAbis) {
+                if (supportedAbi.equals(abi)) {
+                    matched = true;
+                    break;
+                }
+            }
+
+            if (!matched) {
+                System.err.println("Error: abi " + abi + " not supported on this device.");
+                return;
+            }
+        }
+
         final ContainerEncryptionParams encryptionParams;
         if (algo != null || iv != null || key != null || macAlgo != null || macKey != null
                 || tag != null) {
@@ -976,8 +999,9 @@
             VerificationParams verificationParams = new VerificationParams(verificationURI,
                     originatingURI, referrerURI, VerificationParams.NO_UID, null);
 
-            mPm.installPackageWithVerificationAndEncryptionEtc(apkURI, null, obs, installFlags,
-                    installerPackageName, verificationParams, encryptionParams);
+            mPm.installPackageWithVerificationEncryptionAndAbiOverrideEtc(apkURI, null,
+                    obs, installFlags, installerPackageName, verificationParams,
+                    encryptionParams, abi);
 
             synchronized (obs) {
                 while (!obs.finished) {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4f335bb..e03224c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -75,6 +75,8 @@
 import android.media.AudioManager;
 import android.media.MediaRouter;
 import android.media.session.MediaSessionManager;
+import android.media.tv.ITvInputManager;
+import android.media.tv.TvInputManager;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
 import android.net.EthernetManager;
@@ -119,8 +121,6 @@
 import android.service.fingerprint.FingerprintManagerReceiver;
 import android.service.fingerprint.FingerprintService;
 import android.telephony.TelephonyManager;
-import android.tv.ITvInputManager;
-import android.tv.TvInputManager;
 import android.content.ClipboardManager;
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c69e669..a040efb 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2751,11 +2751,11 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
-     * {@link android.tv.TvInputManager} for interacting with TV inputs on the
-     * device.
+     * {@link android.media.tv.TvInputManager} for interacting with TV inputs
+     * on the device.
      *
      * @see #getSystemService
-     * @see android.tv.TvInputManager
+     * @see android.media.tv.TvInputManager
      */
     public static final String TV_INPUT_SERVICE = "tv_input";
 
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 44a6a5d..70668e1 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -433,6 +433,13 @@
             in VerificationParams verificationParams,
             in ContainerEncryptionParams encryptionParams);
 
+    void installPackageWithVerificationEncryptionAndAbiOverrideEtc(in Uri packageURI,
+            in IPackageInstallObserver observer, in IPackageInstallObserver2 observer2,
+            int flags, in String installerPackageName,
+            in VerificationParams verificationParams,
+            in ContainerEncryptionParams encryptionParams,
+	    in String packageAbiOverride);
+
     int installExistingPackageAsUser(String packageName, int userId);
 
     void verifyPendingInstall(int id, int verificationCode);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 24844ba..a48a388 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -905,7 +905,7 @@
         return null;
     }
 
-    private int networkTypeForNetworkCapabilities(NetworkCapabilities netCap) {
+    private int legacyTypeForNetworkCapabilities(NetworkCapabilities netCap) {
         if (netCap == null) return TYPE_NONE;
         if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
             return TYPE_MOBILE_CBS;
@@ -928,6 +928,9 @@
         if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
             return TYPE_MOBILE_HIPRI;
         }
+        if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P)) {
+            return TYPE_WIFI_P2P;
+        }
         return TYPE_NONE;
     }
 
@@ -988,7 +991,7 @@
 
     private NetworkRequest requestNetworkForFeatureLocked(NetworkCapabilities netCap) {
         int delay = -1;
-        int type = networkTypeForNetworkCapabilities(netCap);
+        int type = legacyTypeForNetworkCapabilities(netCap);
         try {
             delay = mService.getRestoreDefaultNetworkDelay(type);
         } catch (RemoteException e) {}
@@ -997,7 +1000,7 @@
         l.delay = delay;
         l.expireSequenceNumber = 0;
         l.networkRequest = sendRequestForNetwork(netCap, l.networkCallbackListener, 0,
-                REQUEST, true);
+                REQUEST, type);
         if (l.networkRequest == null) return null;
         sLegacyRequests.put(netCap, l);
         sendExpireMsgForFeature(netCap, l.expireSequenceNumber, delay);
@@ -2144,7 +2147,7 @@
 
     private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
             NetworkCallbackListener networkCallbackListener, int timeoutSec, int action,
-            boolean legacy) {
+            int legacyType) {
         NetworkRequest networkRequest = null;
         if (networkCallbackListener == null) {
             throw new IllegalArgumentException("null NetworkCallbackListener");
@@ -2157,7 +2160,7 @@
                         new Binder());
             } else {
                 networkRequest = mService.requestNetwork(need, new Messenger(sCallbackHandler),
-                        timeoutSec, new Binder(), legacy);
+                        timeoutSec, new Binder(), legacyType);
             }
             if (networkRequest != null) {
                 synchronized(sNetworkCallbackListener) {
@@ -2187,7 +2190,7 @@
      */
     public NetworkRequest requestNetwork(NetworkCapabilities need,
             NetworkCallbackListener networkCallbackListener) {
-        return sendRequestForNetwork(need, networkCallbackListener, 0, REQUEST, false);
+        return sendRequestForNetwork(need, networkCallbackListener, 0, REQUEST, TYPE_NONE);
     }
 
     /**
@@ -2210,7 +2213,8 @@
      */
     public NetworkRequest requestNetwork(NetworkCapabilities need,
             NetworkCallbackListener networkCallbackListener, int timeoutSec) {
-        return sendRequestForNetwork(need, networkCallbackListener, timeoutSec, REQUEST, false);
+        return sendRequestForNetwork(need, networkCallbackListener, timeoutSec, REQUEST,
+                TYPE_NONE);
     }
 
     /**
@@ -2288,7 +2292,7 @@
      */
     public NetworkRequest listenForNetwork(NetworkCapabilities need,
             NetworkCallbackListener networkCallbackListener) {
-        return sendRequestForNetwork(need, networkCallbackListener, 0, LISTEN, false);
+        return sendRequestForNetwork(need, networkCallbackListener, 0, LISTEN, TYPE_NONE);
     }
 
     /**
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index b67ae88..5f1ff3e 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -158,7 +158,7 @@
             in NetworkCapabilities nc, int score);
 
     NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities,
-            in Messenger messenger, int timeoutSec, in IBinder binder, boolean legacy);
+            in Messenger messenger, int timeoutSec, in IBinder binder, int legacy);
 
     NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities,
             in PendingIntent operation);
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index ccc56e2..d279412 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -188,6 +188,15 @@
     }
 
     /**
+     * @hide
+     */
+    public void setType(int type) {
+        synchronized (this) {
+            mNetworkType = type;
+        }
+    }
+
+    /**
      * Return a network-type-specific integer describing the subtype
      * of the network.
      * @return the network subtype
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 480cb057..47377e9 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -47,19 +47,19 @@
     public final int requestId;
 
     /**
-     * Set for legacy requests and the default.
+     * Set for legacy requests and the default.  Set to TYPE_NONE for none.
      * Causes CONNECTIVITY_ACTION broadcasts to be sent.
      * @hide
      */
-    public final boolean needsBroadcasts;
+    public final int legacyType;
 
     /**
      * @hide
      */
-    public NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts, int rId) {
+    public NetworkRequest(NetworkCapabilities nc, int legacyType, int rId) {
         requestId = rId;
         networkCapabilities = nc;
-        this.needsBroadcasts = needsBroadcasts;
+        this.legacyType = legacyType;
     }
 
     /**
@@ -68,7 +68,7 @@
     public NetworkRequest(NetworkRequest that) {
         networkCapabilities = new NetworkCapabilities(that.networkCapabilities);
         requestId = that.requestId;
-        needsBroadcasts = that.needsBroadcasts;
+        this.legacyType = that.legacyType;
     }
 
     // implement the Parcelable interface
@@ -77,16 +77,16 @@
     }
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeParcelable(networkCapabilities, flags);
-        dest.writeInt(needsBroadcasts ? 1 : 0);
+        dest.writeInt(legacyType);
         dest.writeInt(requestId);
     }
     public static final Creator<NetworkRequest> CREATOR =
         new Creator<NetworkRequest>() {
             public NetworkRequest createFromParcel(Parcel in) {
                 NetworkCapabilities nc = (NetworkCapabilities)in.readParcelable(null);
-                boolean needsBroadcasts = (in.readInt() == 1);
+                int legacyType = in.readInt();
                 int requestId = in.readInt();
-                NetworkRequest result = new NetworkRequest(nc, needsBroadcasts, requestId);
+                NetworkRequest result = new NetworkRequest(nc, legacyType, requestId);
                 return result;
             }
             public NetworkRequest[] newArray(int size) {
@@ -95,14 +95,14 @@
         };
 
     public String toString() {
-        return "NetworkRequest [ id=" + requestId + ", needsBroadcasts=" + needsBroadcasts +
+        return "NetworkRequest [ id=" + requestId + ", legacyType=" + legacyType +
                 ", " + networkCapabilities.toString() + " ]";
     }
 
     public boolean equals(Object obj) {
         if (obj instanceof NetworkRequest == false) return false;
         NetworkRequest that = (NetworkRequest)obj;
-        return (that.needsBroadcasts == this.needsBroadcasts &&
+        return (that.legacyType == this.legacyType &&
                 that.requestId == this.requestId &&
                 ((that.networkCapabilities == null && this.networkCapabilities == null) ||
                  (that.networkCapabilities != null &&
@@ -110,7 +110,7 @@
     }
 
     public int hashCode() {
-        return requestId + (needsBroadcasts ? 1013 : 2026) +
+        return requestId + (legacyType * 1013) +
                 (networkCapabilities.hashCode() * 1051);
     }
 }
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 424d860..5056097 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -75,22 +75,10 @@
     // Constructors
     ///////////////////////////////////////////////////////////////////////////
 
-    /**
-     * Creates a canvas to render directly on screen.
-     */
-    GLES20Canvas(boolean translucent) {
-        this(false, translucent);
-    }
-    
-    protected GLES20Canvas(boolean record, boolean translucent) {
-        mOpaque = !translucent;
-
-        if (record) {
-            mRenderer = nCreateDisplayListRenderer();
-        } else {
-            mRenderer = nCreateRenderer();
-        }
-
+    // TODO: Merge with GLES20RecordingCanvas
+    protected GLES20Canvas() {
+        mOpaque = false;
+        mRenderer = nCreateDisplayListRenderer();
         setupFinalizer();
     }
 
@@ -102,7 +90,6 @@
         }
     }
 
-    private static native long nCreateRenderer();
     private static native long nCreateDisplayListRenderer();
     private static native void nResetDisplayListRenderer(long renderer);
     private static native void nDestroyRenderer(long renderer);
@@ -131,36 +118,6 @@
     private static native void nSetProperty(String name, String value);
 
     ///////////////////////////////////////////////////////////////////////////
-    // Hardware layers
-    ///////////////////////////////////////////////////////////////////////////
-
-    @Override
-    void pushLayerUpdate(HardwareLayer layer) {
-        nPushLayerUpdate(mRenderer, layer.getLayer());
-    }
-
-    @Override
-    void cancelLayerUpdate(HardwareLayer layer) {
-        nCancelLayerUpdate(mRenderer, layer.getLayer());
-    }
-
-    @Override
-    void flushLayerUpdates() {
-        nFlushLayerUpdates(mRenderer);
-    }
-
-    @Override
-    void clearLayerUpdates() {
-        nClearLayerUpdates(mRenderer);
-    }
-
-    static native boolean nCopyLayer(long layerId, long bitmap);
-    private static native void nClearLayerUpdates(long renderer);
-    private static native void nFlushLayerUpdates(long renderer);
-    private static native void nPushLayerUpdate(long renderer, long layer);
-    private static native void nCancelLayerUpdate(long renderer, long layer);
-
-    ///////////////////////////////////////////////////////////////////////////
     // Canvas management
     ///////////////////////////////////////////////////////////////////////////
 
@@ -234,20 +191,6 @@
 
     private static native void nFinish(long renderer);
 
-    /**
-     * Returns the size of the stencil buffer required by the underlying
-     * implementation.
-     * 
-     * @return The minimum number of bits the stencil buffer must. Always >= 0.
-     * 
-     * @hide
-     */
-    public static int getStencilSize() {
-        return nGetStencilSize();
-    }
-
-    private static native int nGetStencilSize();
-
     ///////////////////////////////////////////////////////////////////////////
     // Functor
     ///////////////////////////////////////////////////////////////////////////
@@ -284,49 +227,6 @@
      */
     static final int FLUSH_CACHES_FULL = 2;
 
-    /**
-     * Flush caches to reclaim as much memory as possible. The amount of memory
-     * to reclaim is indicate by the level parameter.
-     * 
-     * The level can be one of {@link #FLUSH_CACHES_MODERATE} or
-     * {@link #FLUSH_CACHES_FULL}.
-     * 
-     * @param level Hint about the amount of memory to reclaim
-     */
-    static void flushCaches(int level) {
-        nFlushCaches(level);
-    }
-
-    private static native void nFlushCaches(int level);
-
-    /**
-     * Release all resources associated with the underlying caches. This should
-     * only be called after a full flushCaches().
-     * 
-     * @hide
-     */
-    static void terminateCaches() {
-        nTerminateCaches();
-    }
-
-    private static native void nTerminateCaches();
-
-    static boolean initCaches() {
-        return nInitCaches();
-    }
-
-    private static native boolean nInitCaches();
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Atlas
-    ///////////////////////////////////////////////////////////////////////////
-
-    static void initAtlas(GraphicBuffer buffer, long[] map) {
-        nInitAtlas(buffer, map, map.length);
-    }
-
-    private static native void nInitAtlas(GraphicBuffer buffer, long[] map, int count);
-
     ///////////////////////////////////////////////////////////////////////////
     // Display list
     ///////////////////////////////////////////////////////////////////////////
@@ -899,12 +799,6 @@
     private static native void nDrawPath(long renderer, long path, long paint);
     private static native void nDrawRects(long renderer, long region, long paint);
 
-    void drawRects(float[] rects, int count, Paint paint) {
-        nDrawRects(mRenderer, rects, count, paint.mNativePaint);
-    }
-
-    private static native void nDrawRects(long renderer, float[] rects, int count, long paint);
-
     @Override
     public void drawPicture(Picture picture) {
         if (picture.createdFromStream) {
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index a94ec3a..b2961e5 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -36,7 +36,7 @@
     RenderNode mNode;
 
     private GLES20RecordingCanvas() {
-        super(true, true);
+        super();
     }
 
     static GLES20RecordingCanvas obtain(@NonNull RenderNode node) {
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
deleted file mode 100644
index f1163e2..0000000
--- a/core/java/android/view/GLRenderer.java
+++ /dev/null
@@ -1,1521 +0,0 @@
-/*
- * Copyright (C) 2013 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.view;
-
-import static javax.microedition.khronos.egl.EGL10.EGL_ALPHA_SIZE;
-import static javax.microedition.khronos.egl.EGL10.EGL_BAD_NATIVE_WINDOW;
-import static javax.microedition.khronos.egl.EGL10.EGL_BLUE_SIZE;
-import static javax.microedition.khronos.egl.EGL10.EGL_CONFIG_CAVEAT;
-import static javax.microedition.khronos.egl.EGL10.EGL_DEFAULT_DISPLAY;
-import static javax.microedition.khronos.egl.EGL10.EGL_DEPTH_SIZE;
-import static javax.microedition.khronos.egl.EGL10.EGL_DRAW;
-import static javax.microedition.khronos.egl.EGL10.EGL_GREEN_SIZE;
-import static javax.microedition.khronos.egl.EGL10.EGL_HEIGHT;
-import static javax.microedition.khronos.egl.EGL10.EGL_NONE;
-import static javax.microedition.khronos.egl.EGL10.EGL_NO_CONTEXT;
-import static javax.microedition.khronos.egl.EGL10.EGL_NO_DISPLAY;
-import static javax.microedition.khronos.egl.EGL10.EGL_NO_SURFACE;
-import static javax.microedition.khronos.egl.EGL10.EGL_RED_SIZE;
-import static javax.microedition.khronos.egl.EGL10.EGL_RENDERABLE_TYPE;
-import static javax.microedition.khronos.egl.EGL10.EGL_SAMPLES;
-import static javax.microedition.khronos.egl.EGL10.EGL_SAMPLE_BUFFERS;
-import static javax.microedition.khronos.egl.EGL10.EGL_STENCIL_SIZE;
-import static javax.microedition.khronos.egl.EGL10.EGL_SUCCESS;
-import static javax.microedition.khronos.egl.EGL10.EGL_SURFACE_TYPE;
-import static javax.microedition.khronos.egl.EGL10.EGL_WIDTH;
-import static javax.microedition.khronos.egl.EGL10.EGL_WINDOW_BIT;
-
-import android.content.ComponentCallbacks2;
-import android.graphics.Bitmap;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.SurfaceTexture;
-import android.opengl.EGL14;
-import android.opengl.GLUtils;
-import android.opengl.ManagedEGLContext;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.Trace;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.Surface.OutOfResourcesException;
-
-import com.google.android.gles_jni.EGLImpl;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.locks.ReentrantLock;
-
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGL11;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-import javax.microedition.khronos.egl.EGLSurface;
-import javax.microedition.khronos.opengles.GL;
-
-/**
- * Hardware renderer using OpenGL
- *
- * @hide
- */
-public class GLRenderer extends HardwareRenderer {
-    static final int SURFACE_STATE_ERROR = 0;
-    static final int SURFACE_STATE_SUCCESS = 1;
-    static final int SURFACE_STATE_UPDATED = 2;
-
-    static final int FUNCTOR_PROCESS_DELAY = 4;
-
-    /**
-     * Number of frames to profile.
-     */
-    private static final int PROFILE_MAX_FRAMES = 128;
-
-    /**
-     * Number of floats per profiled frame.
-     */
-    private static final int PROFILE_FRAME_DATA_COUNT = 3;
-
-    private static final int PROFILE_DRAW_MARGIN = 0;
-    private static final int PROFILE_DRAW_WIDTH = 3;
-    private static final int[] PROFILE_DRAW_COLORS = { 0xcf3e66cc, 0xcfdc3912, 0xcfe69800 };
-    private static final int PROFILE_DRAW_CURRENT_FRAME_COLOR = 0xcf5faa4d;
-    private static final int PROFILE_DRAW_THRESHOLD_COLOR = 0xff5faa4d;
-    private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
-    private static final int PROFILE_DRAW_DP_PER_MS = 7;
-
-    private static final String[] VISUALIZERS = {
-            PROFILE_PROPERTY_VISUALIZE_BARS,
-    };
-
-    private static final String[] OVERDRAW = {
-            OVERDRAW_PROPERTY_SHOW,
-    };
-    private static final int GL_VERSION = 2;
-
-    static EGL10 sEgl;
-    static EGLDisplay sEglDisplay;
-    static EGLConfig sEglConfig;
-    static final Object[] sEglLock = new Object[0];
-    int mWidth = -1, mHeight = -1;
-
-    static final ThreadLocal<ManagedEGLContext> sEglContextStorage
-            = new ThreadLocal<ManagedEGLContext>();
-
-    EGLContext mEglContext;
-    Thread mEglThread;
-
-    EGLSurface mEglSurface;
-
-    GL mGl;
-    HardwareCanvas mCanvas;
-
-    String mName;
-
-    long mFrameCount;
-    Paint mDebugPaint;
-
-    static boolean sDirtyRegions;
-    static final boolean sDirtyRegionsRequested;
-    static {
-        String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
-        //noinspection PointlessBooleanExpression,ConstantConditions
-        sDirtyRegions = "true".equalsIgnoreCase(dirtyProperty);
-        sDirtyRegionsRequested = sDirtyRegions;
-    }
-
-    boolean mDirtyRegionsEnabled;
-    boolean mUpdateDirtyRegions;
-
-    boolean mProfileEnabled;
-    int mProfileVisualizerType = -1;
-    float[] mProfileData;
-    ReentrantLock mProfileLock;
-    int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
-
-    GraphDataProvider mDebugDataProvider;
-    float[][] mProfileShapes;
-    Paint mProfilePaint;
-
-    boolean mDebugDirtyRegions;
-    int mDebugOverdraw = -1;
-
-    final boolean mTranslucent;
-
-    private boolean mDestroyed;
-
-    private final Rect mRedrawClip = new Rect();
-
-    private final int[] mSurfaceSize = new int[2];
-
-    private long mDrawDelta = Long.MAX_VALUE;
-
-    private GLES20Canvas mGlCanvas;
-
-    private DisplayMetrics mDisplayMetrics;
-
-    private static EGLSurface sPbuffer;
-    private static final Object[] sPbufferLock = new Object[0];
-
-    private List<HardwareLayer> mLayerUpdates = new ArrayList<HardwareLayer>();
-
-    private static class GLRendererEglContext extends ManagedEGLContext {
-        final Handler mHandler = new Handler();
-
-        public GLRendererEglContext(EGLContext context) {
-            super(context);
-        }
-
-        @Override
-        public void onTerminate(final EGLContext eglContext) {
-            // Make sure we do this on the correct thread.
-            if (mHandler.getLooper() != Looper.myLooper()) {
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        onTerminate(eglContext);
-                    }
-                });
-                return;
-            }
-
-            synchronized (sEglLock) {
-                if (sEgl == null) return;
-
-                if (EGLImpl.getInitCount(sEglDisplay) == 1) {
-                    usePbufferSurface(eglContext);
-                    GLES20Canvas.terminateCaches();
-
-                    sEgl.eglDestroyContext(sEglDisplay, eglContext);
-                    sEglContextStorage.set(null);
-                    sEglContextStorage.remove();
-
-                    sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
-                    sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
-                            EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
-                    sEgl.eglReleaseThread();
-                    sEgl.eglTerminate(sEglDisplay);
-
-                    sEgl = null;
-                    sEglDisplay = null;
-                    sEglConfig = null;
-                    sPbuffer = null;
-                }
-            }
-        }
-    }
-
-    HardwareCanvas createCanvas() {
-        return mGlCanvas = new GLES20Canvas(mTranslucent);
-    }
-
-    ManagedEGLContext createManagedContext(EGLContext eglContext) {
-        return new GLRendererEglContext(mEglContext);
-    }
-
-    int[] getConfig(boolean dirtyRegions) {
-        //noinspection PointlessBooleanExpression,ConstantConditions
-        final int stencilSize = GLES20Canvas.getStencilSize();
-        final int swapBehavior = dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
-
-        return new int[] {
-                EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
-                EGL_RED_SIZE, 8,
-                EGL_GREEN_SIZE, 8,
-                EGL_BLUE_SIZE, 8,
-                EGL_ALPHA_SIZE, 8,
-                EGL_DEPTH_SIZE, 0,
-                EGL_CONFIG_CAVEAT, EGL_NONE,
-                EGL_STENCIL_SIZE, stencilSize,
-                EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
-                EGL_NONE
-        };
-    }
-
-    void initCaches() {
-        if (GLES20Canvas.initCaches()) {
-            // Caches were (re)initialized, rebind atlas
-            initAtlas();
-        }
-    }
-
-    void initAtlas() {
-        IBinder binder = ServiceManager.getService("assetatlas");
-        if (binder == null) return;
-
-        IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
-        try {
-            if (atlas.isCompatible(android.os.Process.myPpid())) {
-                GraphicBuffer buffer = atlas.getBuffer();
-                if (buffer != null) {
-                    long[] map = atlas.getMap();
-                    if (map != null) {
-                        GLES20Canvas.initAtlas(buffer, map);
-                    }
-                    // If IAssetAtlas is not the same class as the IBinder
-                    // we are using a remote service and we can safely
-                    // destroy the graphic buffer
-                    if (atlas.getClass() != binder.getClass()) {
-                        buffer.destroy();
-                    }
-                }
-            }
-        } catch (RemoteException e) {
-            Log.w(LOG_TAG, "Could not acquire atlas", e);
-        }
-    }
-
-    boolean canDraw() {
-        return mGl != null && mCanvas != null && mGlCanvas != null;
-    }
-
-    int onPreDraw(Rect dirty) {
-        return mGlCanvas.onPreDraw(dirty);
-    }
-
-    void onPostDraw() {
-        mGlCanvas.onPostDraw();
-    }
-
-    void drawProfileData(View.AttachInfo attachInfo) {
-        if (mDebugDataProvider != null) {
-            final GraphDataProvider provider = mDebugDataProvider;
-            initProfileDrawData(attachInfo, provider);
-
-            final int height = provider.getVerticalUnitSize();
-            final int margin = provider.getHorizontaUnitMargin();
-            final int width = provider.getHorizontalUnitSize();
-
-            int x = 0;
-            int count = 0;
-            int current = 0;
-
-            final float[] data = provider.getData();
-            final int elementCount = provider.getElementCount();
-            final int graphType = provider.getGraphType();
-
-            int totalCount = provider.getFrameCount() * elementCount;
-            if (graphType == GraphDataProvider.GRAPH_TYPE_LINES) {
-                totalCount -= elementCount;
-            }
-
-            for (int i = 0; i < totalCount; i += elementCount) {
-                if (data[i] < 0.0f) break;
-
-                int index = count * 4;
-                if (i == provider.getCurrentFrame() * elementCount) current = index;
-
-                x += margin;
-                int x2 = x + width;
-
-                int y2 = mHeight;
-                int y1 = (int) (y2 - data[i] * height);
-
-                switch (graphType) {
-                    case GraphDataProvider.GRAPH_TYPE_BARS: {
-                        for (int j = 0; j < elementCount; j++) {
-                            //noinspection MismatchedReadAndWriteOfArray
-                            final float[] r = mProfileShapes[j];
-                            r[index] = x;
-                            r[index + 1] = y1;
-                            r[index + 2] = x2;
-                            r[index + 3] = y2;
-
-                            y2 = y1;
-                            if (j < elementCount - 1) {
-                                y1 = (int) (y2 - data[i + j + 1] * height);
-                            }
-                        }
-                    } break;
-                    case GraphDataProvider.GRAPH_TYPE_LINES: {
-                        for (int j = 0; j < elementCount; j++) {
-                            //noinspection MismatchedReadAndWriteOfArray
-                            final float[] r = mProfileShapes[j];
-                            r[index] = (x + x2) * 0.5f;
-                            r[index + 1] = index == 0 ? y1 : r[index - 1];
-                            r[index + 2] = r[index] + width;
-                            r[index + 3] = y1;
-
-                            y2 = y1;
-                            if (j < elementCount - 1) {
-                                y1 = (int) (y2 - data[i + j + 1] * height);
-                            }
-                        }
-                    } break;
-                }
-
-
-                x += width;
-                count++;
-            }
-
-            x += margin;
-
-            drawGraph(graphType, count);
-            drawCurrentFrame(graphType, current);
-            drawThreshold(x, height);
-        }
-    }
-
-    private void drawGraph(int graphType, int count) {
-        for (int i = 0; i < mProfileShapes.length; i++) {
-            mDebugDataProvider.setupGraphPaint(mProfilePaint, i);
-            switch (graphType) {
-                case GraphDataProvider.GRAPH_TYPE_BARS:
-                    mGlCanvas.drawRects(mProfileShapes[i], count * 4, mProfilePaint);
-                    break;
-                case GraphDataProvider.GRAPH_TYPE_LINES:
-                    mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint);
-                    break;
-            }
-        }
-    }
-
-    private void drawCurrentFrame(int graphType, int index) {
-        if (index >= 0) {
-            mDebugDataProvider.setupCurrentFramePaint(mProfilePaint);
-            switch (graphType) {
-                case GraphDataProvider.GRAPH_TYPE_BARS:
-                    mGlCanvas.drawRect(mProfileShapes[2][index], mProfileShapes[2][index + 1],
-                            mProfileShapes[2][index + 2], mProfileShapes[0][index + 3],
-                            mProfilePaint);
-                    break;
-                case GraphDataProvider.GRAPH_TYPE_LINES:
-                    mGlCanvas.drawLine(mProfileShapes[2][index], mProfileShapes[2][index + 1],
-                            mProfileShapes[2][index], mHeight, mProfilePaint);
-                    break;
-            }
-        }
-    }
-
-    private void drawThreshold(int x, int height) {
-        float threshold = mDebugDataProvider.getThreshold();
-        if (threshold > 0.0f) {
-            mDebugDataProvider.setupThresholdPaint(mProfilePaint);
-            int y = (int) (mHeight - threshold * height);
-            mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint);
-        }
-    }
-
-    private void initProfileDrawData(View.AttachInfo attachInfo, GraphDataProvider provider) {
-        if (mProfileShapes == null) {
-            final int elementCount = provider.getElementCount();
-            final int frameCount = provider.getFrameCount();
-
-            mProfileShapes = new float[elementCount][];
-            for (int i = 0; i < elementCount; i++) {
-                mProfileShapes[i] = new float[frameCount * 4];
-            }
-
-            mProfilePaint = new Paint();
-        }
-
-        mProfilePaint.reset();
-        if (provider.getGraphType() == GraphDataProvider.GRAPH_TYPE_LINES) {
-            mProfilePaint.setAntiAlias(true);
-        }
-
-        if (mDisplayMetrics == null) {
-            mDisplayMetrics = new DisplayMetrics();
-        }
-
-        attachInfo.mDisplay.getMetrics(mDisplayMetrics);
-        provider.prepare(mDisplayMetrics);
-    }
-
-    @Override
-    void destroy(boolean full) {
-        try {
-            if (full && mCanvas != null) {
-                mCanvas = null;
-            }
-
-            if (!isEnabled() || mDestroyed) {
-                setEnabled(false);
-                return;
-            }
-
-            destroySurface();
-            setEnabled(false);
-
-            mDestroyed = true;
-            mGl = null;
-        } finally {
-            if (full && mGlCanvas != null) {
-                mGlCanvas = null;
-            }
-        }
-    }
-
-    @Override
-    void pushLayerUpdate(HardwareLayer layer) {
-        mLayerUpdates.add(layer);
-    }
-
-    @Override
-    void flushLayerUpdates() {
-        if (validate()) {
-            flushLayerChanges();
-            mGlCanvas.flushLayerUpdates();
-        }
-    }
-
-    @Override
-    HardwareLayer createTextureLayer() {
-        validate();
-        return HardwareLayer.createTextureLayer(this);
-    }
-
-    @Override
-    public HardwareLayer createDisplayListLayer(int width, int height) {
-        validate();
-        return HardwareLayer.createDisplayListLayer(this, width, height);
-    }
-
-    boolean hasContext() {
-        return sEgl != null && mEglContext != null
-                && mEglContext.equals(sEgl.eglGetCurrentContext());
-    }
-
-    @Override
-    void onLayerDestroyed(HardwareLayer layer) {
-        if (mGlCanvas != null) {
-            mGlCanvas.cancelLayerUpdate(layer);
-        }
-        mLayerUpdates.remove(layer);
-    }
-
-    @Override
-    public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
-        return layer.createSurfaceTexture();
-    }
-
-    @Override
-    boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) {
-        if (!validate()) {
-            throw new IllegalStateException("Could not acquire hardware rendering context");
-        }
-        layer.flushChanges();
-        return GLES20Canvas.nCopyLayer(layer.getLayer(), bitmap.mNativeBitmap);
-    }
-
-    @Override
-    boolean safelyRun(Runnable action) {
-        boolean needsContext = !isEnabled() || checkRenderContext() == SURFACE_STATE_ERROR;
-
-        if (needsContext) {
-            GLRendererEglContext managedContext =
-                    (GLRendererEglContext) sEglContextStorage.get();
-            if (managedContext == null) return false;
-            usePbufferSurface(managedContext.getContext());
-        }
-
-        try {
-            action.run();
-        } finally {
-            if (needsContext) {
-                sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
-                        EGL_NO_SURFACE, EGL_NO_CONTEXT);
-            }
-        }
-
-        return true;
-    }
-
-    @Override
-    void invokeFunctor(long functor, boolean waitForCompletion) {
-        boolean needsContext = !isEnabled() || checkRenderContext() == SURFACE_STATE_ERROR;
-        boolean hasContext = !needsContext;
-
-        if (needsContext) {
-            GLRendererEglContext managedContext =
-                    (GLRendererEglContext) sEglContextStorage.get();
-            if (managedContext != null) {
-                usePbufferSurface(managedContext.getContext());
-                hasContext = true;
-            }
-        }
-
-        try {
-            nInvokeFunctor(functor, hasContext);
-        } finally {
-            if (needsContext) {
-                sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
-                        EGL_NO_SURFACE, EGL_NO_CONTEXT);
-            }
-        }
-    }
-
-    private static native void nInvokeFunctor(long functor, boolean hasContext);
-
-    @Override
-    void destroyHardwareResources(final View view) {
-        if (view != null) {
-            safelyRun(new Runnable() {
-                @Override
-                public void run() {
-                    if (mCanvas != null) {
-                        mCanvas.clearLayerUpdates();
-                    }
-                    destroyResources(view);
-                    GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
-                }
-            });
-        }
-    }
-
-    private static void destroyResources(View view) {
-        view.destroyHardwareResources();
-
-        if (view instanceof ViewGroup) {
-            ViewGroup group = (ViewGroup) view;
-
-            int count = group.getChildCount();
-            for (int i = 0; i < count; i++) {
-                destroyResources(group.getChildAt(i));
-            }
-        }
-    }
-
-    static void startTrimMemory(int level) {
-        if (sEgl == null || sEglConfig == null) return;
-
-        GLRendererEglContext managedContext =
-                (GLRendererEglContext) sEglContextStorage.get();
-        // We do not have OpenGL objects
-        if (managedContext == null) {
-            return;
-        } else {
-            usePbufferSurface(managedContext.getContext());
-        }
-
-        if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
-            GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
-        } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
-            GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
-        }
-    }
-
-    static void endTrimMemory() {
-        if (sEgl != null && sEglDisplay != null) {
-            sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-        }
-    }
-
-    private static void usePbufferSurface(EGLContext eglContext) {
-        synchronized (sPbufferLock) {
-            // Create a temporary 1x1 pbuffer so we have a context
-            // to clear our OpenGL objects
-            if (sPbuffer == null) {
-                sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
-                        EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
-                });
-            }
-        }
-        sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
-    }
-
-    GLRenderer(boolean translucent) {
-        mTranslucent = translucent;
-
-        loadSystemProperties();
-    }
-
-    @Override
-    void setOpaque(boolean opaque) {
-        // Not supported
-    }
-
-    @Override
-    boolean loadSystemProperties() {
-        boolean value;
-        boolean changed = false;
-
-        String profiling = SystemProperties.get(PROFILE_PROPERTY);
-        int graphType = search(VISUALIZERS, profiling);
-        value = graphType >= 0;
-
-        if (graphType != mProfileVisualizerType) {
-            changed = true;
-            mProfileVisualizerType = graphType;
-
-            mProfileShapes = null;
-            mProfilePaint = null;
-
-            if (value) {
-                mDebugDataProvider = new GraphDataProvider(graphType);
-            } else {
-                mDebugDataProvider = null;
-            }
-        }
-
-        // If on-screen profiling is not enabled, we need to check whether
-        // console profiling only is enabled
-        if (!value) {
-            value = Boolean.parseBoolean(profiling);
-        }
-
-        if (value != mProfileEnabled) {
-            changed = true;
-            mProfileEnabled = value;
-
-            if (mProfileEnabled) {
-                Log.d(LOG_TAG, "Profiling hardware renderer");
-
-                int maxProfileFrames = SystemProperties.getInt(PROFILE_MAXFRAMES_PROPERTY,
-                        PROFILE_MAX_FRAMES);
-                mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT];
-                for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
-                    mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
-                }
-
-                mProfileLock = new ReentrantLock();
-            } else {
-                mProfileData = null;
-                mProfileLock = null;
-                mProfileVisualizerType = -1;
-            }
-
-            mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
-        }
-
-        value = SystemProperties.getBoolean(DEBUG_DIRTY_REGIONS_PROPERTY, false);
-        if (value != mDebugDirtyRegions) {
-            changed = true;
-            mDebugDirtyRegions = value;
-
-            if (mDebugDirtyRegions) {
-                Log.d(LOG_TAG, "Debugging dirty regions");
-            }
-        }
-
-        String overdraw = SystemProperties.get(HardwareRenderer.DEBUG_OVERDRAW_PROPERTY);
-        int debugOverdraw = search(OVERDRAW, overdraw);
-        if (debugOverdraw != mDebugOverdraw) {
-            changed = true;
-            mDebugOverdraw = debugOverdraw;
-        }
-
-        if (loadProperties()) {
-            changed = true;
-        }
-
-        return changed;
-    }
-
-    private static int search(String[] values, String value) {
-        for (int i = 0; i < values.length; i++) {
-            if (values[i].equals(value)) return i;
-        }
-        return -1;
-    }
-
-    @Override
-    void dumpGfxInfo(PrintWriter pw, FileDescriptor fd) {
-        if (mProfileEnabled) {
-            pw.printf("\n\tDraw\tProcess\tExecute\n");
-
-            mProfileLock.lock();
-            try {
-                for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
-                    if (mProfileData[i] < 0) {
-                        break;
-                    }
-                    pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
-                            mProfileData[i + 2]);
-                    mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
-                }
-                mProfileCurrentFrame = mProfileData.length;
-            } finally {
-                mProfileLock.unlock();
-            }
-        }
-    }
-
-    /**
-     * Indicates whether this renderer instance can track and update dirty regions.
-     */
-    boolean hasDirtyRegions() {
-        return mDirtyRegionsEnabled;
-    }
-
-    /**
-     * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)}
-     * is invoked and the requested flag is turned off. The error code is
-     * also logged as a warning.
-     */
-    void checkEglErrors() {
-        if (isEnabled()) {
-            checkEglErrorsForced();
-        }
-    }
-
-    private void checkEglErrorsForced() {
-        int error = sEgl.eglGetError();
-        if (error != EGL_SUCCESS) {
-            // something bad has happened revert to
-            // normal rendering.
-            Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error));
-            fallback(error != EGL11.EGL_CONTEXT_LOST);
-        }
-    }
-
-    private void fallback(boolean fallback) {
-        destroy(true);
-        if (fallback) {
-            // we'll try again if it was context lost
-            setRequested(false);
-            Log.w(LOG_TAG, "Mountain View, we've had a problem here. "
-                    + "Switching back to software rendering.");
-        }
-    }
-
-    @Override
-    boolean initialize(Surface surface) throws OutOfResourcesException {
-        if (isRequested() && !isEnabled()) {
-            boolean contextCreated = initializeEgl();
-            mGl = createEglSurface(surface);
-            mDestroyed = false;
-
-            if (mGl != null) {
-                int err = sEgl.eglGetError();
-                if (err != EGL_SUCCESS) {
-                    destroy(true);
-                    setRequested(false);
-                } else {
-                    if (mCanvas == null) {
-                        mCanvas = createCanvas();
-                    }
-                    setEnabled(true);
-
-                    if (contextCreated) {
-                        initAtlas();
-                    }
-                }
-
-                return mCanvas != null;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    void updateSurface(Surface surface) throws OutOfResourcesException {
-        if (isRequested() && isEnabled()) {
-            createEglSurface(surface);
-        }
-    }
-
-    @Override
-    void pauseSurface(Surface surface) {
-        // No-op
-    }
-
-    boolean initializeEgl() {
-        synchronized (sEglLock) {
-            if (sEgl == null && sEglConfig == null) {
-                sEgl = (EGL10) EGLContext.getEGL();
-
-                // Get to the default display.
-                sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
-
-                if (sEglDisplay == EGL_NO_DISPLAY) {
-                    throw new RuntimeException("eglGetDisplay failed "
-                            + GLUtils.getEGLErrorString(sEgl.eglGetError()));
-                }
-
-                // We can now initialize EGL for that display
-                int[] version = new int[2];
-                if (!sEgl.eglInitialize(sEglDisplay, version)) {
-                    throw new RuntimeException("eglInitialize failed " +
-                            GLUtils.getEGLErrorString(sEgl.eglGetError()));
-                }
-
-                checkEglErrorsForced();
-
-                sEglConfig = loadEglConfig();
-            }
-        }
-
-        ManagedEGLContext managedContext = sEglContextStorage.get();
-        mEglContext = managedContext != null ? managedContext.getContext() : null;
-        mEglThread = Thread.currentThread();
-
-        if (mEglContext == null) {
-            mEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
-            sEglContextStorage.set(createManagedContext(mEglContext));
-            return true;
-        }
-
-        return false;
-    }
-
-    private EGLConfig loadEglConfig() {
-        EGLConfig eglConfig = chooseEglConfig();
-        if (eglConfig == null) {
-            // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
-            if (sDirtyRegions) {
-                sDirtyRegions = false;
-                eglConfig = chooseEglConfig();
-                if (eglConfig == null) {
-                    throw new RuntimeException("eglConfig not initialized");
-                }
-            } else {
-                throw new RuntimeException("eglConfig not initialized");
-            }
-        }
-        return eglConfig;
-    }
-
-    private EGLConfig chooseEglConfig() {
-        EGLConfig[] configs = new EGLConfig[1];
-        int[] configsCount = new int[1];
-        int[] configSpec = getConfig(sDirtyRegions);
-
-        // Debug
-        final String debug = SystemProperties.get(PRINT_CONFIG_PROPERTY, "");
-        if ("all".equalsIgnoreCase(debug)) {
-            sEgl.eglChooseConfig(sEglDisplay, configSpec, null, 0, configsCount);
-
-            EGLConfig[] debugConfigs = new EGLConfig[configsCount[0]];
-            sEgl.eglChooseConfig(sEglDisplay, configSpec, debugConfigs,
-                    configsCount[0], configsCount);
-
-            for (EGLConfig config : debugConfigs) {
-                printConfig(config);
-            }
-        }
-
-        if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
-            throw new IllegalArgumentException("eglChooseConfig failed " +
-                    GLUtils.getEGLErrorString(sEgl.eglGetError()));
-        } else if (configsCount[0] > 0) {
-            if ("choice".equalsIgnoreCase(debug)) {
-                printConfig(configs[0]);
-            }
-            return configs[0];
-        }
-
-        return null;
-    }
-
-    private static void printConfig(EGLConfig config) {
-        int[] value = new int[1];
-
-        Log.d(LOG_TAG, "EGL configuration " + config + ":");
-
-        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_RED_SIZE, value);
-        Log.d(LOG_TAG, "  RED_SIZE = " + value[0]);
-
-        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_GREEN_SIZE, value);
-        Log.d(LOG_TAG, "  GREEN_SIZE = " + value[0]);
-
-        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_BLUE_SIZE, value);
-        Log.d(LOG_TAG, "  BLUE_SIZE = " + value[0]);
-
-        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_ALPHA_SIZE, value);
-        Log.d(LOG_TAG, "  ALPHA_SIZE = " + value[0]);
-
-        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_DEPTH_SIZE, value);
-        Log.d(LOG_TAG, "  DEPTH_SIZE = " + value[0]);
-
-        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_STENCIL_SIZE, value);
-        Log.d(LOG_TAG, "  STENCIL_SIZE = " + value[0]);
-
-        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLE_BUFFERS, value);
-        Log.d(LOG_TAG, "  SAMPLE_BUFFERS = " + value[0]);
-
-        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLES, value);
-        Log.d(LOG_TAG, "  SAMPLES = " + value[0]);
-
-        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SURFACE_TYPE, value);
-        Log.d(LOG_TAG, "  SURFACE_TYPE = 0x" + Integer.toHexString(value[0]));
-
-        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_CONFIG_CAVEAT, value);
-        Log.d(LOG_TAG, "  CONFIG_CAVEAT = 0x" + Integer.toHexString(value[0]));
-    }
-
-    GL createEglSurface(Surface surface) throws OutOfResourcesException {
-        // Check preconditions.
-        if (sEgl == null) {
-            throw new RuntimeException("egl not initialized");
-        }
-        if (sEglDisplay == null) {
-            throw new RuntimeException("eglDisplay not initialized");
-        }
-        if (sEglConfig == null) {
-            throw new RuntimeException("eglConfig not initialized");
-        }
-        if (Thread.currentThread() != mEglThread) {
-            throw new IllegalStateException("HardwareRenderer cannot be used "
-                    + "from multiple threads");
-        }
-
-        // In case we need to destroy an existing surface
-        destroySurface();
-
-        // Create an EGL surface we can render into.
-        if (!createSurface(surface)) {
-            return null;
-        }
-
-        initCaches();
-
-        return mEglContext.getGL();
-    }
-
-    private void enableDirtyRegions() {
-        // If mDirtyRegions is set, this means we have an EGL configuration
-        // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
-        if (sDirtyRegions) {
-            if (!(mDirtyRegionsEnabled = preserveBackBuffer())) {
-                Log.w(LOG_TAG, "Backbuffer cannot be preserved");
-            }
-        } else if (sDirtyRegionsRequested) {
-            // If mDirtyRegions is not set, our EGL configuration does not
-            // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default
-            // swap behavior might be EGL_BUFFER_PRESERVED, which means we
-            // want to set mDirtyRegions. We try to do this only if dirty
-            // regions were initially requested as part of the device
-            // configuration (see RENDER_DIRTY_REGIONS)
-            mDirtyRegionsEnabled = isBackBufferPreserved();
-        }
-    }
-
-    EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
-        final int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, GL_VERSION, EGL_NONE };
-
-        EGLContext context = egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT,
-                attribs);
-        if (context == null || context == EGL_NO_CONTEXT) {
-            //noinspection ConstantConditions
-            throw new IllegalStateException(
-                    "Could not create an EGL context. eglCreateContext failed with error: " +
-                    GLUtils.getEGLErrorString(sEgl.eglGetError()));
-        }
-
-        return context;
-    }
-
-    void destroySurface() {
-        if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
-            if (mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) {
-                sEgl.eglMakeCurrent(sEglDisplay,
-                        EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-            }
-            sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
-            mEglSurface = null;
-        }
-    }
-
-    @Override
-    void invalidate(Surface surface) {
-        // Cancels any existing buffer to ensure we'll get a buffer
-        // of the right size before we call eglSwapBuffers
-        sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
-        if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
-            sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
-            mEglSurface = null;
-            setEnabled(false);
-        }
-
-        if (surface.isValid()) {
-            if (!createSurface(surface)) {
-                return;
-            }
-
-            mUpdateDirtyRegions = true;
-
-            if (mCanvas != null) {
-                setEnabled(true);
-            }
-        }
-    }
-
-    private boolean createSurface(Surface surface) {
-        mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, surface, null);
-
-        if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
-            int error = sEgl.eglGetError();
-            if (error == EGL_BAD_NATIVE_WINDOW) {
-                Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
-                return false;
-            }
-            throw new RuntimeException("createWindowSurface failed "
-                    + GLUtils.getEGLErrorString(error));
-        }
-
-        if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
-            throw new IllegalStateException("eglMakeCurrent failed " +
-                    GLUtils.getEGLErrorString(sEgl.eglGetError()));
-        }
-
-        enableDirtyRegions();
-
-        return true;
-    }
-
-    boolean validate() {
-        return checkRenderContext() != SURFACE_STATE_ERROR;
-    }
-
-    @Override
-    void setup(int width, int height, float lightX, float lightY, float lightZ, float lightRadius) {
-        if (validate()) {
-            mCanvas.setViewport(width, height);
-            mCanvas.initializeLight(lightX, lightY, lightZ, lightRadius);
-            mWidth = width;
-            mHeight = height;
-        }
-    }
-
-    @Override
-    int getWidth() {
-        return mWidth;
-    }
-
-    @Override
-    int getHeight() {
-        return mHeight;
-    }
-
-    @Override
-    void setName(String name) {
-        mName = name;
-    }
-
-    @Override
-    void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
-            Rect dirty) {
-        if (canDraw()) {
-            if (!hasDirtyRegions()) {
-                dirty = null;
-            }
-            attachInfo.mIgnoreDirtyState = true;
-            attachInfo.mDrawingTime = SystemClock.uptimeMillis();
-
-            view.mPrivateFlags |= View.PFLAG_DRAWN;
-
-            // We are already on the correct thread
-            final int surfaceState = checkRenderContextUnsafe();
-            if (surfaceState != SURFACE_STATE_ERROR) {
-                HardwareCanvas canvas = mCanvas;
-
-                if (mProfileEnabled) {
-                    mProfileLock.lock();
-                }
-
-                dirty = beginFrame(canvas, dirty, surfaceState);
-
-                RenderNode displayList = buildDisplayList(view, canvas);
-
-                flushLayerChanges();
-
-                // buildDisplayList() calls into user code which can cause
-                // an eglMakeCurrent to happen with a different surface/context.
-                // We must therefore check again here.
-                if (checkRenderContextUnsafe() == SURFACE_STATE_ERROR) {
-                    return;
-                }
-
-                int saveCount = 0;
-                int status = RenderNode.STATUS_DONE;
-
-                long start = getSystemTime();
-                try {
-                    status = prepareFrame(dirty);
-
-                    saveCount = canvas.save();
-                    callbacks.onHardwarePreDraw(canvas);
-
-                    if (displayList != null) {
-                        status |= drawDisplayList(canvas, displayList, status);
-                    } else {
-                        // Shouldn't reach here
-                        view.draw(canvas);
-                    }
-                } catch (Exception e) {
-                    Log.e(LOG_TAG, "An error has occurred while drawing:", e);
-                } finally {
-                    callbacks.onHardwarePostDraw(canvas);
-                    canvas.restoreToCount(saveCount);
-                    view.mRecreateDisplayList = false;
-
-                    mDrawDelta = getSystemTime() - start;
-
-                    if (mDrawDelta > 0) {
-                        mFrameCount++;
-
-                        debugDirtyRegions(dirty, canvas);
-                        drawProfileData(attachInfo);
-                    }
-                }
-
-                onPostDraw();
-
-                swapBuffers(status);
-
-                if (mProfileEnabled) {
-                    mProfileLock.unlock();
-                }
-
-                attachInfo.mIgnoreDirtyState = false;
-            }
-        }
-    }
-
-    private void flushLayerChanges() {
-        // Loop through and apply any pending layer changes
-        for (int i = 0; i < mLayerUpdates.size(); i++) {
-            HardwareLayer layer = mLayerUpdates.get(i);
-            layer.flushChanges();
-            if (!layer.isValid()) {
-                // The layer was removed from mAttachedLayers, rewind i by 1
-                // Note that this shouldn't actually happen as View.getHardwareLayer()
-                // is already flushing for error checking reasons
-                i--;
-            } else if (layer.hasDisplayList()) {
-                mCanvas.pushLayerUpdate(layer);
-            }
-        }
-        mLayerUpdates.clear();
-    }
-
-    @Override
-    void fence() {
-        // Everything is immediate, so this is a no-op
-    }
-
-    private RenderNode buildDisplayList(View view, HardwareCanvas canvas) {
-        view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
-                == View.PFLAG_INVALIDATED;
-        view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
-
-        long buildDisplayListStartTime = startBuildDisplayListProfiling();
-        canvas.clearLayerUpdates();
-
-        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
-        RenderNode renderNode = view.getDisplayList();
-        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-
-        endBuildDisplayListProfiling(buildDisplayListStartTime);
-
-        return renderNode;
-    }
-
-    private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
-        // We had to change the current surface and/or context, redraw everything
-        if (surfaceState == SURFACE_STATE_UPDATED) {
-            dirty = null;
-            beginFrame(null);
-        } else {
-            int[] size = mSurfaceSize;
-            beginFrame(size);
-
-            if (size[1] != mHeight || size[0] != mWidth) {
-                mWidth = size[0];
-                mHeight = size[1];
-
-                canvas.setViewport(mWidth, mHeight);
-
-                dirty = null;
-            }
-        }
-
-        if (mDebugDataProvider != null) dirty = null;
-
-        return dirty;
-    }
-
-    private long startBuildDisplayListProfiling() {
-        if (mProfileEnabled) {
-            mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
-            if (mProfileCurrentFrame >= mProfileData.length) {
-                mProfileCurrentFrame = 0;
-            }
-
-            return System.nanoTime();
-        }
-        return 0;
-    }
-
-    private void endBuildDisplayListProfiling(long getDisplayListStartTime) {
-        if (mProfileEnabled) {
-            long now = System.nanoTime();
-            float total = (now - getDisplayListStartTime) * 0.000001f;
-            //noinspection PointlessArithmeticExpression
-            mProfileData[mProfileCurrentFrame] = total;
-        }
-    }
-
-    private int prepareFrame(Rect dirty) {
-        int status;
-        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
-        try {
-            status = onPreDraw(dirty);
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-        }
-        return status;
-    }
-
-    private int drawDisplayList(HardwareCanvas canvas, RenderNode displayList,
-            int status) {
-
-        long drawDisplayListStartTime = 0;
-        if (mProfileEnabled) {
-            drawDisplayListStartTime = System.nanoTime();
-        }
-
-        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
-        nPrepareTree(displayList.getNativeDisplayList());
-        try {
-            status |= canvas.drawDisplayList(displayList, mRedrawClip,
-                    RenderNode.FLAG_CLIP_CHILDREN);
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-        }
-
-        if (mProfileEnabled) {
-            long now = System.nanoTime();
-            float total = (now - drawDisplayListStartTime) * 0.000001f;
-            mProfileData[mProfileCurrentFrame + 1] = total;
-        }
-
-        return status;
-    }
-
-    private void swapBuffers(int status) {
-        if ((status & RenderNode.STATUS_DREW) == RenderNode.STATUS_DREW) {
-            long eglSwapBuffersStartTime = 0;
-            if (mProfileEnabled) {
-                eglSwapBuffersStartTime = System.nanoTime();
-            }
-
-            sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
-
-            if (mProfileEnabled) {
-                long now = System.nanoTime();
-                float total = (now - eglSwapBuffersStartTime) * 0.000001f;
-                mProfileData[mProfileCurrentFrame + 2] = total;
-            }
-
-            checkEglErrors();
-        }
-    }
-
-    private void debugDirtyRegions(Rect dirty, HardwareCanvas canvas) {
-        if (mDebugDirtyRegions) {
-            if (mDebugPaint == null) {
-                mDebugPaint = new Paint();
-                mDebugPaint.setColor(0x7fff0000);
-            }
-
-            if (dirty != null && (mFrameCount & 1) == 0) {
-                canvas.drawRect(dirty, mDebugPaint);
-            }
-        }
-    }
-
-    /**
-     * Ensures the current EGL context and surface are the ones we expect.
-     * This method throws an IllegalStateException if invoked from a thread
-     * that did not initialize EGL.
-     *
-     * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
-     *         {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
-     *         {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
-     *
-     * @see #checkRenderContextUnsafe()
-     */
-    int checkRenderContext() {
-        if (mEglThread != Thread.currentThread()) {
-            throw new IllegalStateException("Hardware acceleration can only be used with a " +
-                    "single UI thread.\nOriginal thread: " + mEglThread + "\n" +
-                    "Current thread: " + Thread.currentThread());
-        }
-
-        return checkRenderContextUnsafe();
-    }
-
-    /**
-     * Ensures the current EGL context and surface are the ones we expect.
-     * This method does not check the current thread.
-     *
-     * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
-     *         {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
-     *         {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
-     *
-     * @see #checkRenderContext()
-     */
-    private int checkRenderContextUnsafe() {
-        if (!mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW)) ||
-                !mEglContext.equals(sEgl.eglGetCurrentContext())) {
-            if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
-                Log.e(LOG_TAG, "eglMakeCurrent failed " +
-                        GLUtils.getEGLErrorString(sEgl.eglGetError()));
-                fallback(true);
-                return SURFACE_STATE_ERROR;
-            } else {
-                if (mUpdateDirtyRegions) {
-                    enableDirtyRegions();
-                    mUpdateDirtyRegions = false;
-                }
-                return SURFACE_STATE_UPDATED;
-            }
-        }
-        return SURFACE_STATE_SUCCESS;
-    }
-
-    private static int dpToPx(int dp, float density) {
-        return (int) (dp * density + 0.5f);
-    }
-
-    static native boolean loadProperties();
-
-    static native void setupShadersDiskCache(String cacheFile);
-
-    /**
-     * Notifies EGL that the frame is about to be rendered.
-     * @param size
-     */
-    static native void beginFrame(int[] size);
-
-    /**
-     * Returns the current system time according to the renderer.
-     * This method is used for debugging only and should not be used
-     * as a clock.
-     */
-    static native long getSystemTime();
-
-    /**
-     * Preserves the back buffer of the current surface after a buffer swap.
-     * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current
-     * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL
-     * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
-     *
-     * @return True if the swap behavior was successfully changed,
-     *         false otherwise.
-     */
-    static native boolean preserveBackBuffer();
-
-    /**
-     * Indicates whether the current surface preserves its back buffer
-     * after a buffer swap.
-     *
-     * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED,
-     *         false otherwise
-     */
-    static native boolean isBackBufferPreserved();
-
-    static native void nDestroyLayer(long layerPtr);
-
-    private static native void nPrepareTree(long displayListPtr);
-
-    class GraphDataProvider {
-        /**
-         * Draws the graph as bars. Frame elements are stacked on top of
-         * each other.
-         */
-        public static final int GRAPH_TYPE_BARS = 0;
-        /**
-         * Draws the graph as lines. The number of series drawn corresponds
-         * to the number of elements.
-         */
-        public static final int GRAPH_TYPE_LINES = 1;
-
-        private final int mGraphType;
-
-        private int mVerticalUnit;
-        private int mHorizontalUnit;
-        private int mHorizontalMargin;
-        private int mThresholdStroke;
-
-        public GraphDataProvider(int graphType) {
-            mGraphType = graphType;
-        }
-
-        void prepare(DisplayMetrics metrics) {
-            final float density = metrics.density;
-
-            mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
-            mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density);
-            mHorizontalMargin = dpToPx(PROFILE_DRAW_MARGIN, density);
-            mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
-        }
-
-        int getGraphType() {
-            return mGraphType;
-        }
-
-        int getVerticalUnitSize() {
-            return mVerticalUnit;
-        }
-
-        int getHorizontalUnitSize() {
-            return mHorizontalUnit;
-        }
-
-        int getHorizontaUnitMargin() {
-            return mHorizontalMargin;
-        }
-
-        float[] getData() {
-            return mProfileData;
-        }
-
-        float getThreshold() {
-            return 16;
-        }
-
-        int getFrameCount() {
-            return mProfileData.length / PROFILE_FRAME_DATA_COUNT;
-        }
-
-        int getElementCount() {
-            return PROFILE_FRAME_DATA_COUNT;
-        }
-
-        int getCurrentFrame() {
-            return mProfileCurrentFrame / PROFILE_FRAME_DATA_COUNT;
-        }
-
-        void setupGraphPaint(Paint paint, int elementIndex) {
-            paint.setColor(PROFILE_DRAW_COLORS[elementIndex]);
-            if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
-        }
-
-        void setupThresholdPaint(Paint paint) {
-            paint.setColor(PROFILE_DRAW_THRESHOLD_COLOR);
-            paint.setStrokeWidth(mThresholdStroke);
-        }
-
-        void setupCurrentFramePaint(Paint paint) {
-            paint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR);
-            if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
-        }
-    }
-}
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index 9568760..b8e7d8c 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -110,48 +110,6 @@
         return RenderNode.STATUS_DONE;
     }
 
-    /**
-     * Indicates that the specified layer must be updated as soon as possible.
-     *
-     * @param layer The layer to update
-     *
-     * @see #clearLayerUpdates()
-     *
-     * @hide
-     */
-    abstract void pushLayerUpdate(HardwareLayer layer);
-
-    /**
-     * Cancels a queued layer update. If the specified layer was not
-     * queued for update, this method has no effect.
-     *
-     * @param layer The layer whose update to cancel
-     *
-     * @see #pushLayerUpdate(HardwareLayer)
-     * @see #clearLayerUpdates()
-     *
-     * @hide
-     */
-    abstract void cancelLayerUpdate(HardwareLayer layer);
-
-    /**
-     * Immediately executes all enqueued layer updates.
-     *
-     * @see #pushLayerUpdate(HardwareLayer)
-     *
-     * @hide
-     */
-    abstract void flushLayerUpdates();
-
-    /**
-     * Removes all enqueued layer updates.
-     *
-     * @see #pushLayerUpdate(HardwareLayer)
-     *
-     * @hide
-     */
-    abstract void clearLayerUpdates();
-
     public abstract void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
             CanvasProperty<Float> radius, CanvasProperty<Paint> paint);
 }
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 652bcd2..6acb134 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -172,24 +172,6 @@
         });
     }
 
-    /**
-     * This exists to minimize impact into the current HardwareLayer paths as
-     * some of the specifics of how to handle error cases in the fully
-     * deferred model will work
-     */
-    @Deprecated
-    public void flushChanges() {
-        if (HardwareRenderer.sUseRenderThread) {
-            // Not supported, don't try.
-            return;
-        }
-
-        boolean success = nFlushChanges(mFinalizer.get());
-        if (!success) {
-            destroy();
-        }
-    }
-
     public long getLayer() {
         return nGetLayer(mFinalizer.get());
     }
@@ -216,33 +198,14 @@
         return st;
     }
 
-    /**
-     * This should only be used by HardwareRenderer! Do not call directly
-     */
-    static HardwareLayer createTextureLayer(HardwareRenderer renderer) {
-        return new HardwareLayer(renderer, nCreateTextureLayer(), LAYER_TYPE_TEXTURE);
-    }
-
     static HardwareLayer adoptTextureLayer(HardwareRenderer renderer, long layer) {
         return new HardwareLayer(renderer, layer, LAYER_TYPE_TEXTURE);
     }
 
-    /**
-     * This should only be used by HardwareRenderer! Do not call directly
-     */
-    static HardwareLayer createDisplayListLayer(HardwareRenderer renderer,
-            int width, int height) {
-        return new HardwareLayer(renderer, nCreateRenderLayer(width, height), LAYER_TYPE_DISPLAY_LIST);
-    }
-
     static HardwareLayer adoptDisplayListLayer(HardwareRenderer renderer, long layer) {
         return new HardwareLayer(renderer, layer, LAYER_TYPE_DISPLAY_LIST);
     }
 
-    /** This also creates the underlying layer */
-    private static native long nCreateTextureLayer();
-    private static native long nCreateRenderLayer(int width, int height);
-
     private static native void nOnTextureDestroyed(long layerUpdater);
 
     private static native boolean nPrepare(long layerUpdater, int width, int height, boolean isOpaque);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index d71de9f..d67c974 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -171,9 +171,6 @@
      */
     public static boolean sSystemRendererDisabled = false;
 
-    /** @hide */
-    public static boolean sUseRenderThread = true;
-
     private boolean mEnabled;
     private boolean mRequested = true;
 
@@ -309,7 +306,7 @@
      * @hide
      */
     public static void setupDiskCache(File cacheDir) {
-        GLRenderer.setupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
+        ThreadedRenderer.setupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
     }
 
     /**
@@ -469,11 +466,7 @@
     static HardwareRenderer create(boolean translucent) {
         HardwareRenderer renderer = null;
         if (GLES20Canvas.isAvailable()) {
-            if (sUseRenderThread) {
-                renderer = new ThreadedRenderer(translucent);
-            } else {
-                renderer = new GLRenderer(translucent);
-            }
+            renderer = new ThreadedRenderer(translucent);
         }
         return renderer;
     }
@@ -500,7 +493,7 @@
      *              see {@link android.content.ComponentCallbacks}
      */
     static void startTrimMemory(int level) {
-        GLRenderer.startTrimMemory(level);
+        ThreadedRenderer.startTrimMemory(level);
     }
 
     /**
@@ -508,7 +501,7 @@
      * cleanup special resources used by the memory trimming process.
      */
     static void endTrimMemory() {
-        GLRenderer.endTrimMemory();
+        ThreadedRenderer.endTrimMemory();
     }
 
     /**
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 11db996..9b3ef7f 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -331,6 +331,14 @@
         }
     }
 
+    static void startTrimMemory(int level) {
+        // TODO
+    }
+
+    static void endTrimMemory() {
+        // TODO
+    }
+
     private static class AtlasInitializer {
         static AtlasInitializer sInstance = new AtlasInitializer();
 
@@ -367,6 +375,8 @@
         }
     }
 
+    static native void setupShadersDiskCache(String cacheFile);
+
     private static native void nSetAtlas(GraphicBuffer buffer, long[] map);
 
     private static native long nCreateRootRenderNode();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ce266d7..b500e46 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13593,12 +13593,6 @@
                 }
             }
 
-            // The layer is not valid if the underlying GPU resources cannot be allocated
-            mHardwareLayer.flushChanges();
-            if (!mHardwareLayer.isValid()) {
-                return null;
-            }
-
             mHardwareLayer.setLayerPaint(mLayerPaint);
             RenderNode displayList = mHardwareLayer.startRecording();
             updateDisplayListIfDirty(displayList, true);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ac25b57..f3d1e3c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -716,17 +716,6 @@
 
             if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
                     && forceHwAccelerated)) {
-                if (!HardwareRenderer.sUseRenderThread) {
-                    // TODO: Delete
-                    // Don't enable hardware acceleration when we're not on the main thread
-                    if (!HardwareRenderer.sSystemRendererDisabled &&
-                            Looper.getMainLooper() != Looper.myLooper()) {
-                        Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
-                                + "acceleration outside of the main thread, aborting");
-                        return;
-                    }
-                }
-
                 if (mAttachInfo.mHardwareRenderer != null) {
                     mAttachInfo.mHardwareRenderer.destroy(true);
                 }
diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl
index 03d3b22..77f0dec 100644
--- a/core/java/com/android/internal/app/IMediaContainerService.aidl
+++ b/core/java/com/android/internal/app/IMediaContainerService.aidl
@@ -25,16 +25,18 @@
 interface IMediaContainerService {
     String copyResourceToContainer(in Uri packageURI, String containerId, String key,
             String resFileName, String publicResFileName, boolean isExternal,
-            boolean isForwardLocked);
+            boolean isForwardLocked, in String abiOverride);
     int copyResource(in Uri packageURI, in ContainerEncryptionParams encryptionParams,
             in ParcelFileDescriptor outStream);
-    PackageInfoLite getMinimalPackageInfo(in String packagePath, in int flags, in long threshold);
+    PackageInfoLite getMinimalPackageInfo(in String packagePath, in int flags, in long threshold,
+            in String abiOverride);
     boolean checkInternalFreeStorage(in Uri fileUri, boolean isForwardLocked, in long threshold);
-    boolean checkExternalFreeStorage(in Uri fileUri, boolean isForwardLocked);
+    boolean checkExternalFreeStorage(in Uri fileUri, boolean isForwardLocked, in String abiOverride);
     ObbInfo getObbInfo(in String filename);
     long calculateDirectorySize(in String directory);
     /** Return file system stats: [0] is total bytes, [1] is available bytes */
     long[] getFileSystemStats(in String path);
     void clearDirectory(in String directory);
-    long calculateInstalledSize(in String packagePath, boolean isForwardLocked);
+    long calculateInstalledSize(in String packagePath, boolean isForwardLocked,
+            in String abiOverride);
 }
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index ba419f9..dab3aff 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -20,6 +20,7 @@
 import android.util.Slog;
 
 import java.io.File;
+import java.io.IOException;
 
 /**
  * Native libraries helper.
@@ -141,4 +142,18 @@
 
         return deletedFiles;
     }
+
+    // We don't care about the other return values for now.
+    private static final int BITCODE_PRESENT = 1;
+
+    public static boolean hasRenderscriptBitcode(ApkHandle handle) throws IOException {
+        final int returnVal = hasRenderscriptBitcode(handle.apkHandle);
+        if (returnVal < 0) {
+            throw new IOException("Error scanning APK, code: " + returnVal);
+        }
+
+        return (returnVal == BITCODE_PRESENT);
+    }
+
+    private static native int hasRenderscriptBitcode(long apkHandle);
 }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index f446c3a..a1cd7f7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -57,7 +57,6 @@
 	android_view_KeyEvent.cpp \
 	android_view_KeyCharacterMap.cpp \
 	android_view_GraphicBuffer.cpp \
-	android_view_GLRenderer.cpp \
 	android_view_GLES20Canvas.cpp \
 	android_view_HardwareLayer.cpp \
 	android_view_ThreadedRenderer.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index e069876..e0c5e96 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -130,7 +130,6 @@
 extern int register_android_view_RenderNodeAnimator(JNIEnv* env);
 extern int register_android_view_GraphicBuffer(JNIEnv* env);
 extern int register_android_view_GLES20Canvas(JNIEnv* env);
-extern int register_android_view_GLRenderer(JNIEnv* env);
 extern int register_android_view_HardwareLayer(JNIEnv* env);
 extern int register_android_view_ThreadedRenderer(JNIEnv* env);
 extern int register_android_view_Surface(JNIEnv* env);
@@ -1214,7 +1213,6 @@
     REG_JNI(register_android_view_RenderNodeAnimator),
     REG_JNI(register_android_view_GraphicBuffer),
     REG_JNI(register_android_view_GLES20Canvas),
-    REG_JNI(register_android_view_GLRenderer),
     REG_JNI(register_android_view_HardwareLayer),
     REG_JNI(register_android_view_ThreadedRenderer),
     REG_JNI(register_android_view_Surface),
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 9141d44..ecdfeb2 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -91,53 +91,9 @@
 } gRectClassInfo;
 
 // ----------------------------------------------------------------------------
-// Caching
-// ----------------------------------------------------------------------------
-
-static void android_view_GLES20Canvas_flushCaches(JNIEnv* env, jobject clazz,
-        jint mode) {
-    if (Caches::hasInstance()) {
-        Caches::getInstance().flush(static_cast<Caches::FlushMode>(mode));
-    }
-}
-
-static jboolean android_view_GLES20Canvas_initCaches(JNIEnv* env, jobject clazz) {
-    if (Caches::hasInstance()) {
-        return Caches::getInstance().init() ? JNI_TRUE : JNI_FALSE;
-    }
-    return JNI_FALSE;
-}
-
-static void android_view_GLES20Canvas_terminateCaches(JNIEnv* env, jobject clazz) {
-    if (Caches::hasInstance()) {
-        Caches::getInstance().terminate();
-    }
-}
-
-// ----------------------------------------------------------------------------
-// Caching
-// ----------------------------------------------------------------------------
-
-static void android_view_GLES20Canvas_initAtlas(JNIEnv* env, jobject clazz,
-        jobject graphicBuffer, jlongArray atlasMapArray, jint count) {
-
-    sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer);
-    jlong* jAtlasMap = env->GetLongArrayElements(atlasMapArray, NULL);
-    Caches::getInstance().assetAtlas.init(buffer, jAtlasMap, count);
-    env->ReleaseLongArrayElements(atlasMapArray, jAtlasMap, 0);
-}
-
-// ----------------------------------------------------------------------------
 // Constructors
 // ----------------------------------------------------------------------------
 
-static jlong android_view_GLES20Canvas_createRenderer(JNIEnv* env, jobject clazz) {
-    RENDERER_LOGD("Create OpenGLRenderer");
-    OpenGLRenderer* renderer = new OpenGLRenderer();
-    renderer->initProperties();
-    return reinterpret_cast<jlong>(renderer);
-}
-
 static void android_view_GLES20Canvas_destroyRenderer(JNIEnv* env, jobject clazz,
         jlong rendererPtr) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
@@ -174,10 +130,6 @@
     renderer->finish();
 }
 
-static jint android_view_GLES20Canvas_getStencilSize(JNIEnv* env, jobject clazz) {
-    return Stencil::getStencilSize();
-}
-
 static void android_view_GLES20Canvas_setProperty(JNIEnv* env,
         jobject clazz, jstring name, jstring value) {
     if (!Caches::hasInstance()) {
@@ -577,15 +529,6 @@
     }
 }
 
-static void android_view_GLES20Canvas_drawRects(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloatArray rects, jint count, jlong paintPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    jfloat* storage = env->GetFloatArrayElements(rects, NULL);
-    SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
-    renderer->drawRects(storage, count, paint);
-    env->ReleaseFloatArrayElements(rects, storage, 0);
-}
-
 static void android_view_GLES20Canvas_drawPoints(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloatArray points, jint offset, jint count, jlong paintPtr) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
@@ -924,39 +867,6 @@
     renderer->drawLayer(layer, x, y);
 }
 
-static jboolean android_view_GLES20Canvas_copyLayer(JNIEnv* env, jobject clazz,
-        jlong layerPtr, jlong bitmapPtr) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
-    return LayerRenderer::copyLayer(layer, bitmap);
-}
-
-static void android_view_GLES20Canvas_pushLayerUpdate(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong layerPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    renderer->pushLayerUpdate(layer);
-}
-
-static void android_view_GLES20Canvas_cancelLayerUpdate(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong layerPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    renderer->cancelLayerUpdate(layer);
-}
-
-static void android_view_GLES20Canvas_clearLayerUpdates(JNIEnv* env, jobject clazz,
-        jlong rendererPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    renderer->clearLayerUpdates();
-}
-
-static void android_view_GLES20Canvas_flushLayerUpdates(JNIEnv* env, jobject clazz,
-        jlong rendererPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    renderer->flushLayerUpdates();
-}
-
 #endif // USE_OPENGL_RENDERER
 
 // ----------------------------------------------------------------------------
@@ -1001,14 +911,7 @@
     { "nIsAvailable",       "()Z",             (void*) android_view_GLES20Canvas_isAvailable },
 
 #ifdef USE_OPENGL_RENDERER
-    { "nFlushCaches",       "(I)V",            (void*) android_view_GLES20Canvas_flushCaches },
-    { "nInitCaches",        "()Z",             (void*) android_view_GLES20Canvas_initCaches },
-    { "nTerminateCaches",   "()V",             (void*) android_view_GLES20Canvas_terminateCaches },
 
-    { "nInitAtlas",         "(Landroid/view/GraphicBuffer;[JI)V",
-            (void*) android_view_GLES20Canvas_initAtlas },
-
-    { "nCreateRenderer",    "()J",             (void*) android_view_GLES20Canvas_createRenderer },
     { "nDestroyRenderer",   "(J)V",            (void*) android_view_GLES20Canvas_destroyRenderer },
     { "nSetViewport",       "(JII)V",          (void*) android_view_GLES20Canvas_setViewport },
     { "nPrepare",           "(JZ)I",           (void*) android_view_GLES20Canvas_prepare },
@@ -1017,9 +920,6 @@
     { "nSetProperty",           "(Ljava/lang/String;Ljava/lang/String;)V",
             (void*) android_view_GLES20Canvas_setProperty },
 
-
-    { "nGetStencilSize",    "()I",             (void*) android_view_GLES20Canvas_getStencilSize },
-
     { "nCallDrawGLFunction", "(JJ)I",          (void*) android_view_GLES20Canvas_callDrawGLFunction },
 
     { "nSave",              "(JI)I",           (void*) android_view_GLES20Canvas_save },
@@ -1059,7 +959,6 @@
     { "nDrawColor",         "(JII)V",          (void*) android_view_GLES20Canvas_drawColor },
     { "nDrawRect",          "(JFFFFJ)V",       (void*) android_view_GLES20Canvas_drawRect },
     { "nDrawRects",         "(JJJ)V",          (void*) android_view_GLES20Canvas_drawRegionAsRects },
-    { "nDrawRects",         "(J[FIJ)V",        (void*) android_view_GLES20Canvas_drawRects },
     { "nDrawRoundRect",     "(JFFFFFFJ)V",     (void*) android_view_GLES20Canvas_drawRoundRect },
     { "nDrawCircle",        "(JFFFJ)V",        (void*) android_view_GLES20Canvas_drawCircle },
     { "nDrawCircle",        "(JJJJJ)V",        (void*) android_view_GLES20Canvas_drawCircleProps },
@@ -1099,11 +998,6 @@
     { "nCreateDisplayListRenderer", "()J",     (void*) android_view_GLES20Canvas_createDisplayListRenderer },
 
     { "nDrawLayer",              "(JJFF)V",    (void*) android_view_GLES20Canvas_drawLayer },
-    { "nCopyLayer",              "(JJ)Z",      (void*) android_view_GLES20Canvas_copyLayer },
-    { "nClearLayerUpdates",      "(J)V",       (void*) android_view_GLES20Canvas_clearLayerUpdates },
-    { "nFlushLayerUpdates",      "(J)V",       (void*) android_view_GLES20Canvas_flushLayerUpdates },
-    { "nPushLayerUpdate",        "(JJ)V",      (void*) android_view_GLES20Canvas_pushLayerUpdate },
-    { "nCancelLayerUpdate",      "(JJ)V",      (void*) android_view_GLES20Canvas_cancelLayerUpdate },
 
     { "nGetMaximumTextureWidth",  "()I",       (void*) android_view_GLES20Canvas_getMaxTextureWidth },
     { "nGetMaximumTextureHeight", "()I",       (void*) android_view_GLES20Canvas_getMaxTextureHeight },
diff --git a/core/jni/android_view_GLRenderer.cpp b/core/jni/android_view_GLRenderer.cpp
deleted file mode 100644
index d0269a3..0000000
--- a/core/jni/android_view_GLRenderer.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "GLRenderer"
-
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <EGL/egl_cache.h>
-
-#include <utils/Timers.h>
-
-#include <private/hwui/DrawGlInfo.h>
-
-#include <Caches.h>
-#include <Extensions.h>
-#include <LayerRenderer.h>
-#include <RenderNode.h>
-
-#ifdef USE_OPENGL_RENDERER
-    EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
-#endif
-
-namespace android {
-
-/**
- * Note: OpenGLRenderer JNI layer is generated and compiled only on supported
- *       devices. This means all the logic must be compiled only when the
- *       preprocessor variable USE_OPENGL_RENDERER is defined.
- */
-#ifdef USE_OPENGL_RENDERER
-
-// ----------------------------------------------------------------------------
-// Defines
-// ----------------------------------------------------------------------------
-
-// Debug
-#define DEBUG_RENDERER 0
-
-// Debug
-#if DEBUG_RENDERER
-    #define RENDERER_LOGD(...) ALOGD(__VA_ARGS__)
-#else
-    #define RENDERER_LOGD(...)
-#endif
-
-// ----------------------------------------------------------------------------
-// Surface and display management
-// ----------------------------------------------------------------------------
-
-static jboolean android_view_GLRenderer_preserveBackBuffer(JNIEnv* env, jobject clazz) {
-    EGLDisplay display = eglGetCurrentDisplay();
-    EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
-
-    eglGetError();
-    eglSurfaceAttrib(display, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
-
-    EGLint error = eglGetError();
-    if (error != EGL_SUCCESS) {
-        RENDERER_LOGD("Could not enable buffer preserved swap behavior (%x)", error);
-    }
-
-    return error == EGL_SUCCESS;
-}
-
-static jboolean android_view_GLRenderer_isBackBufferPreserved(JNIEnv* env, jobject clazz) {
-    EGLDisplay display = eglGetCurrentDisplay();
-    EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
-    EGLint value;
-
-    eglGetError();
-    eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &value);
-
-    EGLint error = eglGetError();
-    if (error != EGL_SUCCESS) {
-        RENDERER_LOGD("Could not query buffer preserved swap behavior (%x)", error);
-    }
-
-    return error == EGL_SUCCESS && value == EGL_BUFFER_PRESERVED;
-}
-
-// ----------------------------------------------------------------------------
-// Tracing and debugging
-// ----------------------------------------------------------------------------
-
-static bool android_view_GLRenderer_loadProperties(JNIEnv* env, jobject clazz) {
-    if (uirenderer::Caches::hasInstance()) {
-        return uirenderer::Caches::getInstance().initProperties();
-    }
-    return false;
-}
-
-static void android_view_GLRenderer_beginFrame(JNIEnv* env, jobject clazz,
-        jintArray size) {
-
-    EGLDisplay display = eglGetCurrentDisplay();
-    EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
-
-    if (size) {
-        EGLint value;
-        jint* storage = env->GetIntArrayElements(size, NULL);
-
-        eglQuerySurface(display, surface, EGL_WIDTH, &value);
-        storage[0] = value;
-
-        eglQuerySurface(display, surface, EGL_HEIGHT, &value);
-        storage[1] = value;
-
-        env->ReleaseIntArrayElements(size, storage, 0);
-    }
-
-    eglBeginFrame(display, surface);
-}
-
-static jlong android_view_GLRenderer_getSystemTime(JNIEnv* env, jobject clazz) {
-    if (uirenderer::Extensions::getInstance().hasNvSystemTime()) {
-        return eglGetSystemTimeNV();
-    }
-    return systemTime(SYSTEM_TIME_MONOTONIC);
-}
-
-static void android_view_GLRenderer_destroyLayer(JNIEnv* env, jobject clazz,
-        jlong layerPtr) {
-    using namespace android::uirenderer;
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    LayerRenderer::destroyLayer(layer);
-}
-
-static void android_view_GLRenderer_prepareTree(JNIEnv* env, jobject clazz,
-        jlong renderNodePtr) {
-    using namespace android::uirenderer;
-    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    TreeInfo ignoredInfo;
-    renderNode->prepareTree(ignoredInfo);
-}
-
-static void android_view_GLRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
-        jlong functorPtr, jboolean hasContext) {
-    using namespace android::uirenderer;
-    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
-    DrawGlInfo::Mode mode = hasContext ? DrawGlInfo::kModeProcess : DrawGlInfo::kModeProcessNoContext;
-    (*functor)(mode, NULL);
-}
-
-#endif // USE_OPENGL_RENDERER
-
-// ----------------------------------------------------------------------------
-// Shaders
-// ----------------------------------------------------------------------------
-
-static void android_view_GLRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
-        jstring diskCachePath) {
-
-    const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
-    egl_cache_t::get()->setCacheFilename(cacheArray);
-    env->ReleaseStringUTFChars(diskCachePath, cacheArray);
-}
-
-// ----------------------------------------------------------------------------
-// JNI Glue
-// ----------------------------------------------------------------------------
-
-const char* const kClassPathName = "android/view/GLRenderer";
-
-static JNINativeMethod gMethods[] = {
-#ifdef USE_OPENGL_RENDERER
-    { "isBackBufferPreserved", "()Z",   (void*) android_view_GLRenderer_isBackBufferPreserved },
-    { "preserveBackBuffer",    "()Z",   (void*) android_view_GLRenderer_preserveBackBuffer },
-    { "loadProperties",        "()Z",   (void*) android_view_GLRenderer_loadProperties },
-
-    { "beginFrame",            "([I)V", (void*) android_view_GLRenderer_beginFrame },
-
-    { "getSystemTime",         "()J",   (void*) android_view_GLRenderer_getSystemTime },
-    { "nDestroyLayer",         "(J)V",  (void*) android_view_GLRenderer_destroyLayer },
-    { "nPrepareTree", "(J)V", (void*) android_view_GLRenderer_prepareTree },
-    { "nInvokeFunctor",        "(JZ)V", (void*) android_view_GLRenderer_invokeFunctor },
-#endif
-
-    { "setupShadersDiskCache", "(Ljava/lang/String;)V",
-            (void*) android_view_GLRenderer_setupShadersDiskCache },
-};
-
-int register_android_view_GLRenderer(JNIEnv* env) {
-    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
-}
-
-};
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 33a2705..879836d 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -43,21 +43,6 @@
 
 #ifdef USE_OPENGL_RENDERER
 
-static jlong android_view_HardwareLayer_createTextureLayer(JNIEnv* env, jobject clazz) {
-    Layer* layer = LayerRenderer::createTextureLayer();
-    if (!layer) return 0;
-
-    return reinterpret_cast<jlong>( new DeferredLayerUpdater(layer) );
-}
-
-static jlong android_view_HardwareLayer_createRenderLayer(JNIEnv* env, jobject clazz,
-        jint width, jint height) {
-    Layer* layer = LayerRenderer::createRenderLayer(width, height);
-    if (!layer) return 0;
-
-    return reinterpret_cast<jlong>( new DeferredLayerUpdater(layer) );
-}
-
 static void android_view_HardwareLayer_onTextureDestroyed(JNIEnv* env, jobject clazz,
         jlong layerUpdaterPtr) {
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
@@ -140,8 +125,6 @@
 static JNINativeMethod gMethods[] = {
 #ifdef USE_OPENGL_RENDERER
 
-    { "nCreateTextureLayer",     "()J",        (void*) android_view_HardwareLayer_createTextureLayer },
-    { "nCreateRenderLayer",      "(II)J",      (void*) android_view_HardwareLayer_createRenderLayer },
     { "nOnTextureDestroyed",     "(J)V",       (void*) android_view_HardwareLayer_onTextureDestroyed },
 
     { "nPrepare",                "(JIIZ)Z",    (void*) android_view_HardwareLayer_prepare },
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 1397131..a550649 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -22,6 +22,10 @@
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <EGL/egl_cache.h>
+
 #include <utils/StrongPointer.h>
 #include <android_runtime/android_view_Surface.h>
 #include <system/window.h>
@@ -329,6 +333,18 @@
 #endif
 
 // ----------------------------------------------------------------------------
+// Shaders
+// ----------------------------------------------------------------------------
+
+static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
+        jstring diskCachePath) {
+
+    const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
+    egl_cache_t::get()->setCacheFilename(cacheArray);
+    env->ReleaseStringUTFChars(diskCachePath, cacheArray);
+}
+
+// ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
 
@@ -361,6 +377,8 @@
     { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
     { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
 #endif
+    { "setupShadersDiskCache", "(Ljava/lang/String;)V",
+                (void*) android_view_ThreadedRenderer_setupShadersDiskCache },
 };
 
 int register_android_view_ThreadedRenderer(JNIEnv* env) {
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 230658f..e55e4ea 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -46,6 +46,9 @@
 #define LIB_SUFFIX ".so"
 #define LIB_SUFFIX_LEN (sizeof(LIB_SUFFIX) - 1)
 
+#define RS_BITCODE_SUFFIX ".bc"
+#define RS_BITCODE_SUFFIX_LEN (sizeof(RS_BITCODE_SUFFIX) -1)
+
 #define GDBSERVER "gdbserver"
 #define GDBSERVER_LEN (sizeof(GDBSERVER) - 1)
 
@@ -486,6 +489,42 @@
     return (jint) findSupportedAbi(env, apkHandle, javaCpuAbisToSearch);
 }
 
+enum bitcode_scan_result_t {
+  APK_SCAN_ERROR = -1,
+  NO_BITCODE_PRESENT = 0,
+  BITCODE_PRESENT = 1,
+};
+
+static jint
+com_android_internal_content_NativeLibraryHelper_hasRenderscriptBitcode(JNIEnv *env, jclass clazz,
+        jlong apkHandle) {
+    ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
+    void* cookie = NULL;
+    if (!zipFile->startIteration(&cookie)) {
+        return APK_SCAN_ERROR;
+    }
+
+    char fileName[PATH_MAX];
+    ZipEntryRO next = NULL;
+    while ((next = zipFile->nextEntry(cookie)) != NULL) {
+        if (zipFile->getEntryFileName(next, fileName, sizeof(fileName))) {
+            continue;
+        }
+
+        const size_t fileNameLen = strlen(fileName);
+        const char* lastSlash = strrchr(fileName, '/');
+        const char* baseName = (lastSlash == NULL) ? fileName : fileName + 1;
+        if (!strncmp(fileName + fileNameLen - RS_BITCODE_SUFFIX_LEN, RS_BITCODE_SUFFIX,
+                     RS_BITCODE_SUFFIX_LEN) && isFilenameSafe(baseName)) {
+            zipFile->endIteration(cookie);
+            return BITCODE_PRESENT;
+        }
+    }
+
+    zipFile->endIteration(cookie);
+    return NO_BITCODE_PRESENT;
+}
+
 static jlong
 com_android_internal_content_NativeLibraryHelper_openApk(JNIEnv *env, jclass, jstring apkPath)
 {
@@ -517,6 +556,8 @@
     {"nativeFindSupportedAbi",
             "(J[Ljava/lang/String;)I",
             (void *)com_android_internal_content_NativeLibraryHelper_findSupportedAbi},
+    {"hasRenderscriptBitcode", "(J)I",
+            (void *)com_android_internal_content_NativeLibraryHelper_hasRenderscriptBitcode},
 };
 
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index bb6a1cb..fe703b2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2076,7 +2076,7 @@
         android:description="@string/permdesc_bindRemoteDisplay"
         android:protectionLevel="signature" />
 
-    <!-- Must be required by a {@link android.tv.TvInputService}
+    <!-- Must be required by a {@link android.media.tv.TvInputService}
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_TV_INPUT"
         android:label="@string/permlab_bindTvInput"
diff --git a/core/res/res/drawable-hdpi/work_icon.png b/core/res/res/drawable-hdpi/work_icon.png
index e90866b..be8a36e 100644
--- a/core/res/res/drawable-hdpi/work_icon.png
+++ b/core/res/res/drawable-hdpi/work_icon.png
Binary files differ
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 489adb4..f1f1802 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4806,6 +4806,8 @@
         <attr name="scaleX" />
         <!-- The amount to scale the group on X coordinate -->
         <attr name="scaleY" />
+        <!-- The alpha of the group (0 is transparent and 1 is opaque) -->
+        <attr name="alpha" />
     </declare-styleable>
 
     <!-- Defines the path used in Vector Drawables. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7234911..9ff67b4 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -457,10 +457,10 @@
     <string name="android_system_label">Android System</string>
 
     <!-- Label for the user owner in the intent forwarding app. -->
-    <string name="user_owner_label">Personal</string>
+    <string name="user_owner_label">Personal apps</string>
 
     <!-- Label for a corporate profile in the intent forwarding app. -->
-    <string name="managed_profile_label">Work</string>
+    <string name="managed_profile_label">Android for Work</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_costMoney">Services that cost you money</string>
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index afd529c..304502e 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -40,6 +40,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.Stack;
 
 /**
  * This lets you create a drawable based on an XML vector graphic It can be
@@ -129,6 +130,8 @@
     private static final int LINEJOIN_ROUND = 1;
     private static final int LINEJOIN_BEVEL = 2;
 
+    private static final boolean DBG_VECTOR_DRAWABLE = false;
+
     private final VectorDrawableState mVectorState;
 
     private int mAlpha = 0xFF;
@@ -279,12 +282,17 @@
         boolean noGroupTag = true;
         boolean noPathTag = true;
 
-        VGroup currentGroup = new VGroup();
+        // Use a stack to help to build the group tree.
+        // The top of the stack is always the current group.
+        final Stack<VGroup> groupStack = new Stack<VGroup>();
+        groupStack.push(pathRenderer.mRootGroup);
 
         int eventType = parser.getEventType();
         while (eventType != XmlPullParser.END_DOCUMENT) {
             if (eventType == XmlPullParser.START_TAG) {
                 final String tagName = parser.getName();
+                final VGroup currentGroup = groupStack.peek();
+
                 if (SHAPE_PATH.equals(tagName)) {
                     final VPath path = new VPath();
                     path.inflate(res, attrs, theme);
@@ -297,18 +305,24 @@
                     pathRenderer.parseViewport(res, attrs);
                     noViewportTag = false;
                 } else if (SHAPE_GROUP.equals(tagName)) {
-                    currentGroup = new VGroup();
-                    currentGroup.inflate(res, attrs, theme);
-                    pathRenderer.mGroupList.add(currentGroup);
+                    VGroup newChildGroup = new VGroup();
+                    newChildGroup.inflate(res, attrs, theme);
+                    currentGroup.mChildGroupList.add(newChildGroup);
+                    groupStack.push(newChildGroup);
                     noGroupTag = false;
                 }
+            } else if (eventType == XmlPullParser.END_TAG) {
+                final String tagName = parser.getName();
+                if (SHAPE_GROUP.equals(tagName)) {
+                    groupStack.pop();
+                }
             }
-
             eventType = parser.next();
         }
 
-        if (noGroupTag && !noPathTag) {
-            pathRenderer.mGroupList.add(currentGroup);
+        // Print the tree out for debug.
+        if (DBG_VECTOR_DRAWABLE) {
+            printGroupTree(pathRenderer.mRootGroup, 0);
         }
 
         if (noSizeTag || noViewportTag || noPathTag) {
@@ -338,6 +352,21 @@
         return pathRenderer;
     }
 
+    private void printGroupTree(VGroup currentGroup, int level) {
+        String indent = "";
+        for (int i = 0 ; i < level ; i++) {
+            indent += "    ";
+        }
+        // Print the current node
+        Log.v(LOGTAG, indent + "current group is :" +  currentGroup.getName()
+                + " rotation is " + currentGroup.mRotate);
+        Log.v(LOGTAG, indent + "matrix is :" +  currentGroup.getLocalMatrix().toString());
+        // Then print all the children
+        for (int i = 0 ; i < currentGroup.mChildGroupList.size(); i++) {
+            printGroupTree(currentGroup.mChildGroupList.get(i), level + 1);
+        }
+    }
+
     private void setPathRenderer(VPathRenderer pathRenderer) {
         mVectorState.mVPathRenderer = pathRenderer;
     }
@@ -350,6 +379,7 @@
         public VectorDrawableState(VectorDrawableState copy) {
             if (copy != null) {
                 mChangingConfigurations = copy.mChangingConfigurations;
+                // TODO: Make sure the constant state are handled correctly.
                 mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
                 mPadding = new Rect(copy.mPadding);
             }
@@ -377,28 +407,42 @@
     }
 
     private static class VPathRenderer {
+        /* Right now the internal data structure is organized as a tree.
+         * Each node can be a group node, or a path.
+         * A group node can have groups or paths as children, but a path node has
+         * no children.
+         * One example can be:
+         *                 Root Group
+         *                /    |     \
+         *           Group    Path    Group
+         *          /     \             |
+         *         Path   Path         Path
+         *
+         */
+        private final VGroup mRootGroup;
+
         private final Path mPath = new Path();
         private final Path mRenderPath = new Path();
-        private final Matrix mMatrix = new Matrix();
+        private static final Matrix IDENTITY_MATRIX = new Matrix();
 
         private Paint mStrokePaint;
         private Paint mFillPaint;
         private ColorFilter mColorFilter;
         private PathMeasure mPathMeasure;
 
-        final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>();
+        private float mBaseWidth = 0;
+        private float mBaseHeight = 0;
+        private float mViewportWidth = 0;
+        private float mViewportHeight = 0;
 
-        float mBaseWidth = 0;
-        float mBaseHeight = 0;
-        float mViewportWidth = 0;
-        float mViewportHeight = 0;
+        private final Matrix mFinalPathMatrix = new Matrix();
 
         public VPathRenderer() {
+            mRootGroup = new VGroup();
         }
 
         public VPathRenderer(VPathRenderer copy) {
-            mGroupList.addAll(copy.mGroupList);
-
+            mRootGroup = copy.mRootGroup;
             mBaseWidth = copy.mBaseWidth;
             mBaseHeight = copy.mBaseHeight;
             mViewportWidth = copy.mViewportHeight;
@@ -406,33 +450,59 @@
         }
 
         public boolean canApplyTheme() {
-            final ArrayList<VGroup> groups = mGroupList;
-            for (int i = groups.size() - 1; i >= 0; i--) {
-                final ArrayList<VPath> paths = groups.get(i).mVGList;
-                for (int j = paths.size() - 1; j >= 0; j--) {
-                    final VPath path = paths.get(j);
-                    if (path.canApplyTheme()) {
-                        return true;
-                    }
+            // If one of the paths can apply theme, then return true;
+            return recursiveCanApplyTheme(mRootGroup);
+        }
+
+        private boolean recursiveCanApplyTheme(VGroup currentGroup) {
+            // We can do a tree traverse here, if there is one path return true,
+            // then we return true for the whole tree.
+            final ArrayList<VPath> paths = currentGroup.mPathList;
+            for (int j = paths.size() - 1; j >= 0; j--) {
+                final VPath path = paths.get(j);
+                if (path.canApplyTheme()) {
+                    return true;
                 }
             }
 
+            final ArrayList<VGroup> childGroups = currentGroup.mChildGroupList;
+
+            for (int i = 0; i < childGroups.size(); i++) {
+                VGroup childGroup = childGroups.get(i);
+                if (childGroup.canApplyTheme()
+                        || recursiveCanApplyTheme(childGroup)) {
+                    return true;
+                }
+            }
             return false;
         }
 
         public void applyTheme(Theme t) {
-            final ArrayList<VGroup> groups = mGroupList;
-            for (int i = groups.size() - 1; i >= 0; i--) {
-                VGroup currentGroup = groups.get(i);
-                currentGroup.applyTheme(t);
-                final ArrayList<VPath> paths = currentGroup.mVGList;
-                for (int j = paths.size() - 1; j >= 0; j--) {
-                    final VPath path = paths.get(j);
-                    if (path.canApplyTheme()) {
-                        path.applyTheme(t);
-                    }
+            // Apply theme to every path of the tree.
+            recursiveApplyTheme(mRootGroup, t);
+        }
+
+        private void recursiveApplyTheme(VGroup currentGroup, Theme t) {
+            // We can do a tree traverse here, apply theme to all paths which
+            // can apply theme.
+            final ArrayList<VPath> paths = currentGroup.mPathList;
+            for (int j = paths.size() - 1; j >= 0; j--) {
+                final VPath path = paths.get(j);
+                if (path.canApplyTheme()) {
+                    path.applyTheme(t);
                 }
             }
+
+            final ArrayList<VGroup> childGroups = currentGroup.mChildGroupList;
+
+            for (int i = 0; i < childGroups.size(); i++) {
+                VGroup childGroup = childGroups.get(i);
+                if (childGroup.canApplyTheme()) {
+                    childGroup.applyTheme(t);
+                }
+                recursiveApplyTheme(childGroup, t);
+            }
+
         }
 
         public void setColorFilter(ColorFilter colorFilter) {
@@ -448,34 +518,35 @@
 
         }
 
-        public void draw(Canvas canvas, int w, int h) {
-            if (mGroupList == null || mGroupList.size() == 0) {
-                Log.e(LOGTAG,"There is no group to draw");
-                return;
-            }
+        private void drawGroupTree(VGroup currentGroup, Matrix currentMatrix,
+                Canvas canvas, int w, int h) {
+            // Calculate current group's matrix by preConcat the parent's and
+            // and the current one on the top of the stack.
+            // Basically the Mfinal = Mviewport * M0 * M1 * M2;
+            // Mi the local matrix at level i of the group tree.
+            currentGroup.mStackedMatrix.set(currentMatrix);
 
-            for (int i = 0; i < mGroupList.size(); i++) {
-                VGroup currentGroup = mGroupList.get(i);
-                if (currentGroup != null) {
-                    drawPath(currentGroup, canvas, w, h);
-                }
+            currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
+
+            drawPath(currentGroup, canvas, w, h);
+            // Draw the group tree in post order.
+            for (int i = 0 ; i < currentGroup.mChildGroupList.size(); i++) {
+                drawGroupTree(currentGroup.mChildGroupList.get(i),
+                        currentGroup.mStackedMatrix, canvas, w, h);
             }
         }
 
+        public void draw(Canvas canvas, int w, int h) {
+            // Travese the tree in pre-order to draw.
+            drawGroupTree(mRootGroup, IDENTITY_MATRIX, canvas, w, h);
+        }
+
         private void drawPath(VGroup vGroup, Canvas canvas, int w, int h) {
             final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
 
-            mMatrix.reset();
-
-            // The order we apply is the same as the
-            // RenderNode.cpp::applyViewPropertyTransforms().
-            mMatrix.postTranslate(-vGroup.mPivotX, -vGroup.mPivotY);
-            mMatrix.postScale(vGroup.mScaleX, vGroup.mScaleY);
-            mMatrix.postRotate(vGroup.mRotate, 0, 0);
-            mMatrix.postTranslate(vGroup.mTranslateX + vGroup.mPivotX, vGroup.mTranslateY + vGroup.mPivotY);
-
-            mMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
-            mMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
+            mFinalPathMatrix.set(vGroup.mStackedMatrix);
+            mFinalPathMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
+            mFinalPathMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
 
             ArrayList<VPath> paths = vGroup.getPaths();
             for (int i = 0; i < paths.size(); i++) {
@@ -507,7 +578,7 @@
 
                 mRenderPath.reset();
 
-                mRenderPath.addPath(path, mMatrix);
+                mRenderPath.addPath(path, mFinalPathMatrix);
 
                 if (vPath.mClip) {
                     canvas.clipPath(mRenderPath, Region.Op.REPLACE);
@@ -588,7 +659,8 @@
 
     private static class VGroup {
         private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
-        private final ArrayList<VPath> mVGList = new ArrayList<VPath>();
+        private final ArrayList<VPath> mPathList = new ArrayList<VPath>();
+        private final ArrayList<VGroup> mChildGroupList = new ArrayList<VGroup>();
 
         private float mRotate = 0;
         private float mPivotX = 0;
@@ -597,15 +669,36 @@
         private float mScaleY = 1;
         private float mTranslateX = 0;
         private float mTranslateY = 0;
+        private float mAlpha = 1;
+
+        // mLocalMatrix is parsed from the XML.
+        private final Matrix mLocalMatrix = new Matrix();
+        // mStackedMatrix is only used when drawing, it combines all the
+        // parents' local matrices with the current one.
+        private final Matrix mStackedMatrix = new Matrix();
 
         private int[] mThemeAttrs;
 
+        private String mName = null;
+
+        public String getName() {
+            return mName;
+        }
+
+        public Matrix getLocalMatrix() {
+            return mLocalMatrix;
+        }
+
         public void add(VPath path) {
             String id = path.getID();
             mVGPathMap.put(id, path);
-            mVGList.add(path);
+            mPathList.add(path);
          }
 
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null;
+        }
+
         public void applyTheme(Theme t) {
             if (mThemeAttrs == null) {
                 return;
@@ -621,6 +714,11 @@
             mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
             mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
             mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
+            mAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mAlpha);
+            updateLocalMatrix();
+            if (a.hasValue(R.styleable.VectorDrawableGroup_name)) {
+                mName = a.getString(R.styleable.VectorDrawableGroup_name);
+            }
             a.recycle();
         }
 
@@ -660,15 +758,34 @@
                 mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
             }
 
+            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_name] == 0) {
+                mName = a.getString(R.styleable.VectorDrawableGroup_name);
+            }
+
+            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_alpha] == 0) {
+                mAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mAlpha);
+            }
+
+            updateLocalMatrix();
             a.recycle();
         }
 
+        private void updateLocalMatrix() {
+            // The order we apply is the same as the
+            // RenderNode.cpp::applyViewPropertyTransforms().
+            mLocalMatrix.reset();
+            mLocalMatrix.postTranslate(-mPivotX, -mPivotY);
+            mLocalMatrix.postScale(mScaleX, mScaleY);
+            mLocalMatrix.postRotate(mRotate, 0, 0);
+            mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
+        }
+
         /**
          * Must return in order of adding
          * @return ordered list of paths
          */
         public ArrayList<VPath> getPaths() {
-            return mVGList;
+            return mPathList;
         }
 
     }
diff --git a/core/java/android/tv/ITvInputClient.aidl b/media/java/android/media/tv/ITvInputClient.aidl
similarity index 94%
rename from core/java/android/tv/ITvInputClient.aidl
rename to media/java/android/media/tv/ITvInputClient.aidl
index ef89c68..dc79a73 100644
--- a/core/java/android/tv/ITvInputClient.aidl
+++ b/media/java/android/media/tv/ITvInputClient.aidl
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
 import android.content.ComponentName;
+import android.media.tv.ITvInputSession;
 import android.os.Bundle;
-import android.tv.ITvInputSession;
 import android.view.InputChannel;
 
 /**
diff --git a/core/java/android/tv/ITvInputHardware.aidl b/media/java/android/media/tv/ITvInputHardware.aidl
similarity index 95%
rename from core/java/android/tv/ITvInputHardware.aidl
rename to media/java/android/media/tv/ITvInputHardware.aidl
index 7250453..f35e8f3 100644
--- a/core/java/android/tv/ITvInputHardware.aidl
+++ b/media/java/android/media/tv/ITvInputHardware.aidl
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
-import android.tv.TvStreamConfig;
+import android.media.tv.TvStreamConfig;
 import android.view.KeyEvent;
 import android.view.Surface;
 
diff --git a/core/java/android/tv/ITvInputHardwareCallback.aidl b/media/java/android/media/tv/ITvInputHardwareCallback.aidl
similarity index 91%
rename from core/java/android/tv/ITvInputHardwareCallback.aidl
rename to media/java/android/media/tv/ITvInputHardwareCallback.aidl
index 83041be..870883b 100644
--- a/core/java/android/tv/ITvInputHardwareCallback.aidl
+++ b/media/java/android/media/tv/ITvInputHardwareCallback.aidl
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
-import android.tv.TvStreamConfig;
+import android.media.tv.TvStreamConfig;
 
 /**
  * @hide
diff --git a/core/java/android/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
similarity index 89%
rename from core/java/android/tv/ITvInputManager.aidl
rename to media/java/android/media/tv/ITvInputManager.aidl
index c6f8d79..6db5a18 100644
--- a/core/java/android/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -14,16 +14,16 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
 import android.content.ComponentName;
 import android.graphics.Rect;
+import android.media.tv.ITvInputHardware;
+import android.media.tv.ITvInputHardwareCallback;
+import android.media.tv.ITvInputClient;
+import android.media.tv.TvInputHardwareInfo;
+import android.media.tv.TvInputInfo;
 import android.net.Uri;
-import android.tv.ITvInputHardware;
-import android.tv.ITvInputHardwareCallback;
-import android.tv.ITvInputClient;
-import android.tv.TvInputHardwareInfo;
-import android.tv.TvInputInfo;
 import android.view.Surface;
 
 /**
diff --git a/core/java/android/tv/ITvInputService.aidl b/media/java/android/media/tv/ITvInputService.aidl
similarity index 88%
rename from core/java/android/tv/ITvInputService.aidl
rename to media/java/android/media/tv/ITvInputService.aidl
index 4f1bc2b..992e424 100644
--- a/core/java/android/tv/ITvInputService.aidl
+++ b/media/java/android/media/tv/ITvInputService.aidl
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
-import android.tv.ITvInputServiceCallback;
-import android.tv.ITvInputSessionCallback;
+import android.media.tv.ITvInputServiceCallback;
+import android.media.tv.ITvInputSessionCallback;
 import android.view.InputChannel;
 
 /**
diff --git a/core/java/android/tv/ITvInputServiceCallback.aidl b/media/java/android/media/tv/ITvInputServiceCallback.aidl
similarity index 96%
rename from core/java/android/tv/ITvInputServiceCallback.aidl
rename to media/java/android/media/tv/ITvInputServiceCallback.aidl
index 71fc780..c9484dd 100644
--- a/core/java/android/tv/ITvInputServiceCallback.aidl
+++ b/media/java/android/media/tv/ITvInputServiceCallback.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
 import android.content.ComponentName;
 
diff --git a/core/java/android/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
similarity index 97%
rename from core/java/android/tv/ITvInputSession.aidl
rename to media/java/android/media/tv/ITvInputSession.aidl
index 32fee4b..fb2e251 100644
--- a/core/java/android/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
 import android.graphics.Rect;
 import android.net.Uri;
diff --git a/core/java/android/tv/ITvInputSessionCallback.aidl b/media/java/android/media/tv/ITvInputSessionCallback.aidl
similarity index 93%
rename from core/java/android/tv/ITvInputSessionCallback.aidl
rename to media/java/android/media/tv/ITvInputSessionCallback.aidl
index e27b8bf..71f2d07 100644
--- a/core/java/android/tv/ITvInputSessionCallback.aidl
+++ b/media/java/android/media/tv/ITvInputSessionCallback.aidl
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
+import android.media.tv.ITvInputSession;
 import android.os.Bundle;
-import android.tv.ITvInputSession;
 
 /**
  * Helper interface for ITvInputSession to allow the TV input to notify the system service when a
diff --git a/core/java/android/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
similarity index 96%
rename from core/java/android/tv/ITvInputSessionWrapper.java
rename to media/java/android/media/tv/ITvInputSessionWrapper.java
index 3ccccf3..975e391 100644
--- a/core/java/android/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -14,22 +14,20 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
 import android.content.Context;
 import android.graphics.Rect;
+import android.media.tv.TvInputManager.Session;
+import android.media.tv.TvInputService.TvInputSessionImpl;
 import android.net.Uri;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
-import android.tv.TvInputManager.Session;
-import android.tv.TvInputService.TvInputSessionImpl;
 import android.util.Log;
 import android.view.InputChannel;
 import android.view.InputEvent;
 import android.view.InputEventReceiver;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
 import android.view.Surface;
 
 import com.android.internal.os.HandlerCaller;
diff --git a/core/java/android/provider/TvContract.java b/media/java/android/media/tv/TvContract.java
similarity index 98%
rename from core/java/android/provider/TvContract.java
rename to media/java/android/media/tv/TvContract.java
index 0d90a16..e9a87ff 100644
--- a/core/java/android/provider/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-package android.provider;
+package android.media.tv;
 
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.net.Uri;
-import android.tv.TvInputService;
+import android.provider.BaseColumns;
 
 import java.util.List;
 
@@ -88,8 +88,8 @@
     /**
      * Builds a URI that points to all browsable channels from a given TV input.
      *
-     * @param name {@link ComponentName} of the {@link android.tv.TvInputService} that implements
-     *            the given TV input.
+     * @param name {@link ComponentName} of the {@link android.media.tv.TvInputService} that
+     *            implements the given TV input.
      */
     public static final Uri buildChannelsUriForInput(ComponentName name) {
         return buildChannelsUriForInput(name, true);
@@ -98,8 +98,8 @@
     /**
      * Builds a URI that points to all or browsable-only channels from a given TV input.
      *
-     * @param name {@link ComponentName} of the {@link android.tv.TvInputService} that implements
-     *            the given TV input.
+     * @param name {@link ComponentName} of the {@link android.media.tv.TvInputService} that
+     *            implements the given TV input.
      * @param browsableOnly If set to {@code true} the URI points to only browsable channels. If set
      *            to {@code false} the URI points to all channels regardless of whether they are
      *            browsable or not.
diff --git a/core/java/android/tv/TvInputHardwareInfo.aidl b/media/java/android/media/tv/TvInputHardwareInfo.aidl
similarity index 95%
rename from core/java/android/tv/TvInputHardwareInfo.aidl
rename to media/java/android/media/tv/TvInputHardwareInfo.aidl
index 484ab60..a4c38bb 100644
--- a/core/java/android/tv/TvInputHardwareInfo.aidl
+++ b/media/java/android/media/tv/TvInputHardwareInfo.aidl
@@ -15,6 +15,6 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
 parcelable TvInputHardwareInfo;
diff --git a/core/java/android/tv/TvInputHardwareInfo.java b/media/java/android/media/tv/TvInputHardwareInfo.java
similarity index 98%
rename from core/java/android/tv/TvInputHardwareInfo.java
rename to media/java/android/media/tv/TvInputHardwareInfo.java
index b0dc58e..4beb960 100644
--- a/core/java/android/tv/TvInputHardwareInfo.java
+++ b/media/java/android/media/tv/TvInputHardwareInfo.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/tv/TvInputInfo.aidl b/media/java/android/media/tv/TvInputInfo.aidl
similarity index 95%
rename from core/java/android/tv/TvInputInfo.aidl
rename to media/java/android/media/tv/TvInputInfo.aidl
index abc4b47..ba139a2 100644
--- a/core/java/android/tv/TvInputInfo.aidl
+++ b/media/java/android/media/tv/TvInputInfo.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
 parcelable TvInputInfo;
diff --git a/core/java/android/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
similarity index 98%
rename from core/java/android/tv/TvInputInfo.java
rename to media/java/android/media/tv/TvInputInfo.java
index 217e4b7..854fea7 100644
--- a/core/java/android/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
diff --git a/core/java/android/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
similarity index 99%
rename from core/java/android/tv/TvInputManager.java
rename to media/java/android/media/tv/TvInputManager.java
index d0c2ca6..1335a1b 100644
--- a/core/java/android/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
 import android.graphics.Rect;
 import android.net.Uri;
diff --git a/core/java/android/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
similarity index 98%
rename from core/java/android/tv/TvInputService.java
rename to media/java/android/media/tv/TvInputService.java
index 03d24db..a3b0273 100644
--- a/core/java/android/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
 import android.app.Service;
 import android.content.ComponentName;
@@ -22,6 +22,8 @@
 import android.content.Intent;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.media.tv.ITvInputService;
+import android.media.tv.TvInputManager.Session;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -29,7 +31,6 @@
 import android.os.Message;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
-import android.tv.TvInputManager.Session;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.InputChannel;
@@ -59,7 +60,7 @@
      * must also require the {@link android.Manifest.permission#BIND_TV_INPUT} permission so that
      * other applications cannot abuse it.
      */
-    public static final String SERVICE_INTERFACE = "android.tv.TvInputService";
+    public static final String SERVICE_INTERFACE = "android.media.tv.TvInputService";
 
     private String mId;
     private final Handler mHandler = new ServiceHandler();
diff --git a/core/java/android/tv/TvStreamConfig.aidl b/media/java/android/media/tv/TvStreamConfig.aidl
similarity index 95%
rename from core/java/android/tv/TvStreamConfig.aidl
rename to media/java/android/media/tv/TvStreamConfig.aidl
index 4d0add4..569fcc0 100644
--- a/core/java/android/tv/TvStreamConfig.aidl
+++ b/media/java/android/media/tv/TvStreamConfig.aidl
@@ -15,6 +15,6 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
 parcelable TvStreamConfig;
\ No newline at end of file
diff --git a/core/java/android/tv/TvStreamConfig.java b/media/java/android/media/tv/TvStreamConfig.java
similarity index 98%
rename from core/java/android/tv/TvStreamConfig.java
rename to media/java/android/media/tv/TvStreamConfig.java
index 03e63b1..7f0c92f 100644
--- a/core/java/android/tv/TvStreamConfig.java
+++ b/media/java/android/media/tv/TvStreamConfig.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/tv/TvView.java b/media/java/android/media/tv/TvView.java
similarity index 98%
rename from core/java/android/tv/TvView.java
rename to media/java/android/media/tv/TvView.java
index 2d31701..126d739 100644
--- a/core/java/android/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -14,16 +14,16 @@
  * limitations under the License.
  */
 
-package android.tv;
+package android.media.tv;
 
 import android.content.Context;
 import android.graphics.Rect;
+import android.media.tv.TvInputManager.Session;
+import android.media.tv.TvInputManager.Session.FinishedInputEventCallback;
+import android.media.tv.TvInputManager.SessionCallback;
 import android.os.Bundle;
 import android.os.Handler;
 import android.text.TextUtils;
-import android.tv.TvInputManager.Session;
-import android.tv.TvInputManager.Session.FinishedInputEventCallback;
-import android.tv.TvInputManager.SessionCallback;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.InputEvent;
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 36c1d5c..ec87c6e 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -88,7 +88,7 @@
     private IMediaContainerService.Stub mBinder = new IMediaContainerService.Stub() {
         /**
          * Creates a new container and copies resource there.
-         * @param paackageURI the uri of resource to be copied. Can be either
+         * @param packageURI the uri of resource to be copied. Can be either
          * a content uri or a file uri
          * @param cid the id of the secure container that should
          * be used for creating a secure container into which the resource
@@ -101,13 +101,13 @@
          */
         public String copyResourceToContainer(final Uri packageURI, final String cid,
                 final String key, final String resFileName, final String publicResFileName,
-                boolean isExternal, boolean isForwardLocked) {
+                boolean isExternal, boolean isForwardLocked, String abiOverride) {
             if (packageURI == null || cid == null) {
                 return null;
             }
 
             return copyResourceInner(packageURI, cid, key, resFileName, publicResFileName,
-                    isExternal, isForwardLocked);
+                    isExternal, isForwardLocked, abiOverride);
         }
 
         /**
@@ -153,13 +153,12 @@
         /**
          * Determine the recommended install location for package
          * specified by file uri location.
-         * @param fileUri the uri of resource to be copied. Should be a
-         * file uri
+         *
          * @return Returns PackageInfoLite object containing
          * the package info and recommended app location.
          */
         public PackageInfoLite getMinimalPackageInfo(final String packagePath, int flags,
-                long threshold) {
+                long threshold, String abiOverride) {
             PackageInfoLite ret = new PackageInfoLite();
 
             if (packagePath == null) {
@@ -191,7 +190,7 @@
             ret.verifiers = pkg.verifiers;
 
             ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation,
-                    packagePath, flags, threshold);
+                    packagePath, flags, threshold, abiOverride);
 
             return ret;
         }
@@ -208,11 +207,11 @@
         }
 
         @Override
-        public boolean checkExternalFreeStorage(Uri packageUri, boolean isForwardLocked)
-                throws RemoteException {
+        public boolean checkExternalFreeStorage(Uri packageUri, boolean isForwardLocked,
+                String abiOverride) throws RemoteException {
             final File apkFile = new File(packageUri.getPath());
             try {
-                return isUnderExternalThreshold(apkFile, isForwardLocked);
+                return isUnderExternalThreshold(apkFile, isForwardLocked, abiOverride);
             } catch (IOException e) {
                 return true;
             }
@@ -265,11 +264,11 @@
         }
 
         @Override
-        public long calculateInstalledSize(String packagePath, boolean isForwardLocked)
-                throws RemoteException {
+        public long calculateInstalledSize(String packagePath, boolean isForwardLocked,
+                String abiOverride) throws RemoteException {
             final File packageFile = new File(packagePath);
             try {
-                return calculateContainerSize(packageFile, isForwardLocked) * 1024 * 1024;
+                return calculateContainerSize(packageFile, isForwardLocked, abiOverride) * 1024 * 1024;
             } catch (IOException e) {
                 /*
                  * Okay, something failed, so let's just estimate it to be 2x
@@ -328,7 +327,8 @@
     }
 
     private String copyResourceInner(Uri packageURI, String newCid, String key, String resFileName,
-            String publicResFileName, boolean isExternal, boolean isForwardLocked) {
+            String publicResFileName, boolean isExternal, boolean isForwardLocked,
+            String abiOverride) {
 
         if (isExternal) {
             // Make sure the sdcard is mounted.
@@ -343,7 +343,22 @@
         String codePath = packageURI.getPath();
         File codeFile = new File(codePath);
         NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(codePath);
-        final int abi = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_ABIS);
+        String[] abiList = Build.SUPPORTED_ABIS;
+        if (abiOverride != null) {
+            abiList = new String[] { abiOverride };
+        } else {
+            try {
+                if (Build.SUPPORTED_64_BIT_ABIS.length > 0 &&
+                        NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
+                    abiList = Build.SUPPORTED_32_BIT_ABIS;
+                }
+            } catch (IOException ioe) {
+                Slog.w(TAG, "Problem determining ABI for: " + codeFile.getPath());
+                return null;
+            }
+        }
+
+        final int abi = NativeLibraryHelper.findSupportedAbi(handle, abiList);
 
         // Calculate size of container needed to hold base APK.
         final int sizeMb;
@@ -414,7 +429,7 @@
             int ret = PackageManager.INSTALL_SUCCEEDED;
             if (abi >= 0) {
                 ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle,
-                        sharedLibraryDir, Build.SUPPORTED_ABIS[abi]);
+                        sharedLibraryDir, abiList[abi]);
             } else if (abi != PackageManager.NO_NATIVE_LIBRARIES) {
                 ret = abi;
             }
@@ -672,7 +687,7 @@
     private static final int PREFER_EXTERNAL = 2;
 
     private int recommendAppInstallLocation(int installLocation, String archiveFilePath, int flags,
-            long threshold) {
+            long threshold, String abiOverride) {
         int prefer;
         boolean checkBoth = false;
 
@@ -741,7 +756,7 @@
         boolean fitsOnSd = false;
         if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)) {
             try {
-                fitsOnSd = isUnderExternalThreshold(apkFile, isForwardLocked);
+                fitsOnSd = isUnderExternalThreshold(apkFile, isForwardLocked, abiOverride);
             } catch (IOException e) {
                 return PackageHelper.RECOMMEND_FAILED_INVALID_URI;
             }
@@ -812,13 +827,13 @@
      * @return true if file fits
      * @throws IOException when file does not exist
      */
-    private boolean isUnderExternalThreshold(File apkFile, boolean isForwardLocked)
+    private boolean isUnderExternalThreshold(File apkFile, boolean isForwardLocked, String abiOverride)
             throws IOException {
         if (Environment.isExternalStorageEmulated()) {
             return false;
         }
 
-        final int sizeMb = calculateContainerSize(apkFile, isForwardLocked);
+        final int sizeMb = calculateContainerSize(apkFile, isForwardLocked, abiOverride);
 
         final int availSdMb;
         if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
@@ -832,9 +847,11 @@
         return availSdMb > sizeMb;
     }
 
-    private int calculateContainerSize(File apkFile, boolean forwardLocked) throws IOException {
+    private int calculateContainerSize(File apkFile, boolean forwardLocked,
+            String abiOverride) throws IOException {
         NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(apkFile);
-        final int abi = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_ABIS);
+        final int abi = NativeLibraryHelper.findSupportedAbi(handle,
+                (abiOverride != null) ? new String[] { abiOverride } : Build.SUPPORTED_ABIS);
 
         try {
             return calculateContainerSize(handle, apkFile, abi, forwardLocked);
diff --git a/packages/Keyguard/Android.mk b/packages/Keyguard/Android.mk
index 1be44f9..96ed2e7 100644
--- a/packages/Keyguard/Android.mk
+++ b/packages/Keyguard/Android.mk
@@ -16,8 +16,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-subdir-Iaidl-files) \
-                   $(call all-proto-files-under,src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-subdir-Iaidl-files)
 
 LOCAL_MODULE := Keyguard
 
@@ -27,9 +26,6 @@
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
-LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
-
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/packages/Keyguard/src/com/android/keyguard/analytics/KeyguardAnalytics.java b/packages/Keyguard/src/com/android/keyguard/analytics/KeyguardAnalytics.java
deleted file mode 100644
index 20af2f1..0000000
--- a/packages/Keyguard/src/com/android/keyguard/analytics/KeyguardAnalytics.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * 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.keyguard.analytics;
-
-import com.google.protobuf.nano.CodedOutputByteBufferNano;
-import com.google.protobuf.nano.MessageNano;
-
-import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.os.AsyncTask;
-import android.util.Log;
-import android.view.MotionEvent;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * Tracks sessions, touch and sensor events in Keyguard.
- *
- * A session starts when the user is presented with the Keyguard and ends when the Keyguard is no
- * longer visible to the user.
- */
-public class KeyguardAnalytics implements SensorEventListener {
-
-    private static final boolean DEBUG = false;
-    private static final String TAG = "KeyguardAnalytics";
-    private static final long TIMEOUT_MILLIS = 11000; // 11 seconds.
-
-    private static final int[] SENSORS = new int[] {
-            Sensor.TYPE_ACCELEROMETER,
-            Sensor.TYPE_GYROSCOPE,
-            Sensor.TYPE_PROXIMITY,
-            Sensor.TYPE_LIGHT,
-            Sensor.TYPE_ROTATION_VECTOR,
-    };
-
-    private Session mCurrentSession = null;
-    // Err on the side of caution, so logging is not started after a crash even tough the screen
-    // is off.
-    private boolean mScreenOn = false;
-    private boolean mHidden = false;
-
-    private final SensorManager mSensorManager;
-    private final SessionTypeAdapter mSessionTypeAdapter;
-    private final File mAnalyticsFile;
-
-    public KeyguardAnalytics(Context context, SessionTypeAdapter sessionTypeAdapter,
-            File analyticsFile) {
-        mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
-        mSessionTypeAdapter = sessionTypeAdapter;
-        mAnalyticsFile = analyticsFile;
-    }
-
-    public Callback getCallback() {
-        return mCallback;
-    }
-
-    public interface Callback {
-        public void onShow();
-        public void onHide();
-        public void onScreenOn();
-        public void onScreenOff();
-        public boolean onTouchEvent(MotionEvent ev, int width, int height);
-        public void onSetOccluded(boolean hidden);
-    }
-
-    public interface SessionTypeAdapter {
-        public int getSessionType();
-    }
-
-    private void sessionEntrypoint() {
-        if (mCurrentSession == null && mScreenOn && !mHidden) {
-            onSessionStart();
-        }
-    }
-
-    private void sessionExitpoint(int result) {
-        if (mCurrentSession != null) {
-            onSessionEnd(result);
-        }
-    }
-
-    private void onSessionStart() {
-        int type = mSessionTypeAdapter.getSessionType();
-        mCurrentSession = new Session(System.currentTimeMillis(), System.nanoTime(), type);
-        if (type == Session.TYPE_KEYGUARD_SECURE) {
-            mCurrentSession.setRedactTouchEvents();
-        }
-        for (int sensorType : SENSORS) {
-            Sensor s = mSensorManager.getDefaultSensor(sensorType);
-            if (s != null) {
-                mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME);
-            }
-        }
-        if (DEBUG) {
-            Log.d(TAG, "onSessionStart()");
-        }
-    }
-
-    private void onSessionEnd(int result) {
-        if (DEBUG) {
-            Log.d(TAG, String.format("onSessionEnd(success=%d)", result));
-        }
-        mSensorManager.unregisterListener(this);
-
-        Session session = mCurrentSession;
-        mCurrentSession = null;
-
-        session.end(System.currentTimeMillis(), result);
-        queueSession(session);
-    }
-
-    private void queueSession(final Session currentSession) {
-        if (DEBUG) {
-            Log.i(TAG, "Saving session.");
-        }
-        new AsyncTask<Void, Void, Void>() {
-            @Override
-            protected Void doInBackground(Void... params) {
-                try {
-                    byte[] b = writeDelimitedProto(currentSession.toProto());
-                    OutputStream os = new FileOutputStream(mAnalyticsFile, true /* append */);
-                    if (DEBUG) {
-                        Log.d(TAG, String.format("Serialized size: %d kB.", b.length / 1024));
-                    }
-                    try {
-                        os.write(b);
-                        os.flush();
-                    } finally {
-                        try {
-                            os.close();
-                        } catch (IOException e) {
-                            Log.e(TAG, "Exception while closing file", e);
-                        }
-                    }
-                } catch (IOException e) {
-                    Log.e(TAG, "Exception while writing file", e);
-                }
-                return null;
-            }
-
-            private byte[] writeDelimitedProto(MessageNano proto)
-                    throws IOException {
-                byte[] result = new byte[CodedOutputByteBufferNano.computeMessageSizeNoTag(proto)];
-                CodedOutputByteBufferNano ob = CodedOutputByteBufferNano.newInstance(result);
-                ob.writeMessageNoTag(proto);
-                ob.checkNoSpaceLeft();
-                return result;
-            }
-        }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
-    }
-
-    @Override
-    public synchronized void onSensorChanged(SensorEvent event) {
-        if (false) {
-            Log.v(TAG, String.format(
-                    "onSensorChanged(name=%s, values[0]=%f)",
-                    event.sensor.getName(), event.values[0]));
-        }
-        if (mCurrentSession != null) {
-            mCurrentSession.addSensorEvent(event, System.nanoTime());
-            enforceTimeout();
-        }
-    }
-
-    private void enforceTimeout() {
-        if (System.currentTimeMillis() - mCurrentSession.getStartTimestampMillis()
-                > TIMEOUT_MILLIS) {
-            onSessionEnd(Session.RESULT_UNKNOWN);
-            if (DEBUG) {
-                Log.i(TAG, "Analytics timed out.");
-            }
-        }
-    }
-
-    @Override
-    public void onAccuracyChanged(Sensor sensor, int accuracy) {
-    }
-
-    private final Callback mCallback = new Callback() {
-        @Override
-        public void onShow() {
-            if (DEBUG) {
-                Log.d(TAG, "onShow()");
-            }
-            synchronized (KeyguardAnalytics.this) {
-                sessionEntrypoint();
-            }
-        }
-
-        @Override
-        public void onHide() {
-            if (DEBUG) {
-                Log.d(TAG, "onHide()");
-            }
-            synchronized (KeyguardAnalytics.this) {
-                sessionExitpoint(Session.RESULT_SUCCESS);
-            }
-        }
-
-        @Override
-        public void onScreenOn() {
-            if (DEBUG) {
-                Log.d(TAG, "onScreenOn()");
-            }
-            synchronized (KeyguardAnalytics.this) {
-                mScreenOn = true;
-                sessionEntrypoint();
-            }
-        }
-
-        @Override
-        public void onScreenOff() {
-            if (DEBUG) {
-                Log.d(TAG, "onScreenOff()");
-            }
-            synchronized (KeyguardAnalytics.this) {
-                mScreenOn = false;
-                sessionExitpoint(Session.RESULT_FAILURE);
-            }
-        }
-
-        @Override
-        public boolean onTouchEvent(MotionEvent ev, int width, int height) {
-            if (DEBUG) {
-                Log.v(TAG, "onTouchEvent(ev.action="
-                        + MotionEvent.actionToString(ev.getAction()) + ")");
-            }
-            synchronized (KeyguardAnalytics.this) {
-                if (mCurrentSession != null) {
-                    mCurrentSession.addMotionEvent(ev);
-                    mCurrentSession.setTouchArea(width, height);
-                    enforceTimeout();
-                }
-            }
-            return true;
-        }
-
-        @Override
-        public void onSetOccluded(boolean hidden) {
-            synchronized (KeyguardAnalytics.this) {
-                if (hidden != mHidden) {
-                    if (DEBUG) {
-                        Log.d(TAG, "onSetOccluded(" + hidden + ")");
-                    }
-                    mHidden = hidden;
-                    if (hidden) {
-                        // Could have gone to camera on purpose / by falsing or an app could have
-                        // launched on top of the lockscreen.
-                        sessionExitpoint(Session.RESULT_UNKNOWN);
-                    } else {
-                        sessionEntrypoint();
-                    }
-                }
-            }
-        }
-    };
-
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/analytics/PointerTracker.java b/packages/Keyguard/src/com/android/keyguard/analytics/PointerTracker.java
deleted file mode 100644
index e68f751..0000000
--- a/packages/Keyguard/src/com/android/keyguard/analytics/PointerTracker.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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.keyguard.analytics;
-
-import android.graphics.RectF;
-import android.util.FloatMath;
-import android.util.SparseArray;
-import android.view.MotionEvent;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static com.android.keyguard.analytics.KeyguardAnalyticsProtos.Session.TouchEvent.BoundingBox;
-
-/**
- * Takes motion events and tracks the length and bounding box of each pointer gesture as well as
- * the bounding box of the whole gesture.
- */
-public class PointerTracker {
-    private SparseArray<Pointer> mPointerInfoMap = new SparseArray<Pointer>();
-    private RectF mTotalBoundingBox = new RectF();
-
-    public void addMotionEvent(MotionEvent ev) {
-        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
-            float x = ev.getX();
-            float y = ev.getY();
-            mTotalBoundingBox.set(x, y, x, y);
-        }
-        for (int i = 0; i < ev.getPointerCount(); i++) {
-            int id = ev.getPointerId(i);
-            Pointer pointer = getPointer(id);
-            float x = ev.getX(i);
-            float y = ev.getY(i);
-            boolean down = ev.getActionMasked() == MotionEvent.ACTION_DOWN
-                    || (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN
-                            && ev.getActionIndex() == i);
-            pointer.addPoint(x, y, down);
-            mTotalBoundingBox.union(x, y);
-        }
-    }
-
-    public float getPointerLength(int id) {
-        return getPointer(id).length;
-    }
-
-    public BoundingBox getBoundingBox() {
-        return boundingBoxFromRect(mTotalBoundingBox);
-    }
-
-    public BoundingBox getPointerBoundingBox(int id) {
-        return boundingBoxFromRect(getPointer(id).boundingBox);
-    }
-
-    private BoundingBox boundingBoxFromRect(RectF f) {
-        BoundingBox bb = new BoundingBox();
-        bb.setHeight(f.height());
-        bb.setWidth(f.width());
-        return bb;
-    }
-
-    private Pointer getPointer(int id) {
-        Pointer p = mPointerInfoMap.get(id);
-        if (p == null) {
-            p = new Pointer();
-            mPointerInfoMap.put(id, p);
-        }
-        return p;
-    }
-
-    private static class Pointer {
-        public float length;
-        public final RectF boundingBox = new RectF();
-
-        private float mLastX;
-        private float mLastY;
-
-        public void addPoint(float x, float y, boolean down) {
-            float deltaX;
-            float deltaY;
-            if (down) {
-                boundingBox.set(x, y, x, y);
-                length = 0f;
-                deltaX = 0;
-                deltaY = 0;
-            } else {
-                deltaX = x - mLastX;
-                deltaY = y - mLastY;
-            }
-            mLastX = x;
-            mLastY = y;
-            length += FloatMath.sqrt(deltaX * deltaX + deltaY * deltaY);
-            boundingBox.union(x, y);
-        }
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/analytics/Session.java b/packages/Keyguard/src/com/android/keyguard/analytics/Session.java
deleted file mode 100644
index 05f9165..0000000
--- a/packages/Keyguard/src/com/android/keyguard/analytics/Session.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * 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.keyguard.analytics;
-
-import android.os.Build;
-import android.util.Slog;
-import android.view.MotionEvent;
-
-import java.util.ArrayList;
-
-import static com.android.keyguard.analytics.KeyguardAnalyticsProtos.Session.SensorEvent;
-import static com.android.keyguard.analytics.KeyguardAnalyticsProtos.Session.TouchEvent;
-
-/**
- * Records data about one keyguard session.
- *
- * The recorded data contains start and end of the session, whether it unlocked the device
- * successfully, sensor data and touch data.
- *
- * If the keyguard is secure, the recorded touch data will correlate or contain the user pattern or
- * PIN. If this is not desired, the touch coordinates can be redacted before serialization.
- */
-public class Session {
-
-    private static final String TAG = "KeyguardAnalytics";
-    private static final boolean DEBUG = false;
-
-    /**
-     * The user has failed to unlock the device in this session.
-     */
-    public static final int RESULT_FAILURE = KeyguardAnalyticsProtos.Session.FAILURE;
-    /**
-     * The user has succeeded in unlocking the device in this session.
-     */
-    public static final int RESULT_SUCCESS = KeyguardAnalyticsProtos.Session.SUCCESS;
-
-    /**
-     * It is unknown how the session with the keyguard ended.
-     */
-    public static final int RESULT_UNKNOWN = KeyguardAnalyticsProtos.Session.UNKNOWN;
-
-    /**
-     * This session took place on an insecure keyguard.
-     */
-    public static final int TYPE_KEYGUARD_INSECURE
-            = KeyguardAnalyticsProtos.Session.KEYGUARD_INSECURE;
-
-    /**
-     * This session took place on an secure keyguard.
-     */
-    public static final int TYPE_KEYGUARD_SECURE
-            = KeyguardAnalyticsProtos.Session.KEYGUARD_SECURE;
-
-    /**
-     * This session took place during a fake wake up of the device.
-     */
-    public static final int TYPE_RANDOM_WAKEUP = KeyguardAnalyticsProtos.Session.RANDOM_WAKEUP;
-
-
-    private final PointerTracker mPointerTracker = new PointerTracker();
-
-    private final long mStartTimestampMillis;
-    private final long mStartSystemTimeNanos;
-    private final int mType;
-
-    private boolean mRedactTouchEvents;
-    private ArrayList<TouchEvent> mMotionEvents = new ArrayList<TouchEvent>(200);
-    private ArrayList<SensorEvent> mSensorEvents = new ArrayList<SensorEvent>(600);
-    private int mTouchAreaHeight;
-    private int mTouchAreaWidth;
-
-    private long mEndTimestampMillis;
-    private int mResult;
-    private boolean mEnded;
-
-    public Session(long startTimestampMillis, long startSystemTimeNanos, int type) {
-        mStartTimestampMillis = startTimestampMillis;
-        mStartSystemTimeNanos = startSystemTimeNanos;
-        mType = type;
-    }
-
-    public void end(long endTimestampMillis, int result) {
-        mEnded = true;
-        mEndTimestampMillis = endTimestampMillis;
-        mResult = result;
-    }
-
-    public void addMotionEvent(MotionEvent motionEvent) {
-        if (mEnded) {
-            return;
-        }
-        mPointerTracker.addMotionEvent(motionEvent);
-        mMotionEvents.add(protoFromMotionEvent(motionEvent));
-    }
-
-    public void addSensorEvent(android.hardware.SensorEvent eventOrig, long systemTimeNanos) {
-        if (mEnded) {
-            return;
-        }
-        SensorEvent event = protoFromSensorEvent(eventOrig, systemTimeNanos);
-        mSensorEvents.add(event);
-        if (DEBUG) {
-            Slog.v(TAG, String.format("addSensorEvent(name=%s, values[0]=%f",
-                    event.getType(), event.values[0]));
-        }
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder("Session{");
-        sb.append("mType=").append(mType);
-        sb.append(", mStartTimestampMillis=").append(mStartTimestampMillis);
-        sb.append(", mStartSystemTimeNanos=").append(mStartSystemTimeNanos);
-        sb.append(", mEndTimestampMillis=").append(mEndTimestampMillis);
-        sb.append(", mResult=").append(mResult);
-        sb.append(", mRedactTouchEvents=").append(mRedactTouchEvents);
-        sb.append(", mTouchAreaHeight=").append(mTouchAreaHeight);
-        sb.append(", mTouchAreaWidth=").append(mTouchAreaWidth);
-        sb.append(", mMotionEvents=[size=").append(mMotionEvents.size()).append("]");
-        sb.append(", mSensorEvents=[size=").append(mSensorEvents.size()).append("]");
-        sb.append('}');
-        return sb.toString();
-    }
-
-    public KeyguardAnalyticsProtos.Session toProto() {
-        KeyguardAnalyticsProtos.Session proto = new KeyguardAnalyticsProtos.Session();
-        proto.setStartTimestampMillis(mStartTimestampMillis);
-        proto.setDurationMillis(mEndTimestampMillis - mStartTimestampMillis);
-        proto.setBuild(Build.FINGERPRINT);
-        proto.setResult(mResult);
-        proto.sensorEvents = mSensorEvents.toArray(proto.sensorEvents);
-        proto.touchEvents = mMotionEvents.toArray(proto.touchEvents);
-        proto.setTouchAreaWidth(mTouchAreaWidth);
-        proto.setTouchAreaHeight(mTouchAreaHeight);
-        proto.setType(mType);
-        if (mRedactTouchEvents) {
-            redactTouchEvents(proto.touchEvents);
-        }
-        return proto;
-    }
-
-    private void redactTouchEvents(TouchEvent[] touchEvents) {
-        for (int i = 0; i < touchEvents.length; i++) {
-            TouchEvent t = touchEvents[i];
-            for (int j = 0; j < t.pointers.length; j++) {
-                TouchEvent.Pointer p = t.pointers[j];
-                p.clearX();
-                p.clearY();
-            }
-            t.setRedacted(true);
-        }
-    }
-
-    private SensorEvent protoFromSensorEvent(android.hardware.SensorEvent ev, long sysTimeNanos) {
-        SensorEvent proto = new SensorEvent();
-        proto.setType(ev.sensor.getType());
-        proto.setTimeOffsetNanos(sysTimeNanos - mStartSystemTimeNanos);
-        proto.setTimestamp(ev.timestamp);
-        proto.values = ev.values.clone();
-        return proto;
-    }
-
-    private TouchEvent protoFromMotionEvent(MotionEvent ev) {
-        int count = ev.getPointerCount();
-        TouchEvent proto = new TouchEvent();
-        proto.setTimeOffsetNanos(ev.getEventTimeNano() - mStartSystemTimeNanos);
-        proto.setAction(ev.getActionMasked());
-        proto.setActionIndex(ev.getActionIndex());
-        proto.pointers = new TouchEvent.Pointer[count];
-        for (int i = 0; i < count; i++) {
-            TouchEvent.Pointer p = new TouchEvent.Pointer();
-            p.setX(ev.getX(i));
-            p.setY(ev.getY(i));
-            p.setSize(ev.getSize(i));
-            p.setPressure(ev.getPressure(i));
-            p.setId(ev.getPointerId(i));
-            proto.pointers[i] = p;
-            if ((ev.getActionMasked() == MotionEvent.ACTION_POINTER_UP && ev.getActionIndex() == i)
-                    || ev.getActionMasked() == MotionEvent.ACTION_UP) {
-                p.boundingBox = mPointerTracker.getPointerBoundingBox(p.getId());
-                p.setLength(mPointerTracker.getPointerLength(p.getId()));
-            }
-        }
-        if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
-            proto.boundingBox = mPointerTracker.getBoundingBox();
-        }
-        return proto;
-    }
-
-    /**
-     * Discards the x / y coordinates of the touch events on serialization. Retained are the
-     * size of the individual and overall bounding boxes and the length of each pointer's gesture.
-     */
-    public void setRedactTouchEvents() {
-        mRedactTouchEvents = true;
-    }
-
-    public void setTouchArea(int width, int height) {
-        mTouchAreaWidth = width;
-        mTouchAreaHeight = height;
-    }
-
-    public long getStartTimestampMillis() {
-        return mStartTimestampMillis;
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/analytics/keyguard_analytics.proto b/packages/Keyguard/src/com/android/keyguard/analytics/keyguard_analytics.proto
deleted file mode 100644
index 68b1590..0000000
--- a/packages/Keyguard/src/com/android/keyguard/analytics/keyguard_analytics.proto
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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
- */
-
-syntax = "proto2";
-
-package keyguard;
-
-option java_package = "com.android.keyguard.analytics";
-option java_outer_classname = "KeyguardAnalyticsProtos";
-
-message Session {
-    message TouchEvent {
-        message BoundingBox {
-            optional float width = 1;
-            optional float height = 2;
-        }
-
-        enum Action {
-            // Keep in sync with MotionEvent.
-            DOWN = 0;
-            UP = 1;
-            MOVE = 2;
-            CANCEL = 3;
-            OUTSIDE = 4;
-            POINTER_DOWN = 5;
-            POINTER_UP = 6;
-        }
-
-        message Pointer {
-            optional float x = 1;
-            optional float y = 2;
-            optional float size = 3;
-            optional float pressure = 4;
-            optional int32 id = 5;
-            optional float length = 6;
-            // Bounding box of the pointer. Only set on UP or POINTER_UP event of this pointer.
-            optional BoundingBox boundingBox = 7;
-        }
-
-        optional uint64 timeOffsetNanos = 1;
-        optional Action action = 2;
-        optional int32 actionIndex = 3;
-        repeated Pointer pointers = 4;
-        /* If true, the the x / y coordinates of the touch events were redacted. Retained are the
-           size of the individual and overall bounding boxes and the length of each pointer's
-           gesture. */
-        optional bool redacted = 5;
-        // Bounding box of the whole gesture. Only set on UP event.
-        optional BoundingBox boundingBox = 6;
-    }
-
-    message SensorEvent {
-        enum Type {
-            ACCELEROMETER = 1;
-            GYROSCOPE = 4;
-            LIGHT = 5;
-            PROXIMITY = 8;
-            ROTATION_VECTOR = 11;
-        }
-
-        optional Type type = 1;
-        optional uint64 timeOffsetNanos = 2;
-        repeated float values = 3;
-        optional uint64 timestamp = 4;
-    }
-
-    enum Result {
-        FAILURE = 0;
-        SUCCESS = 1;
-        UNKNOWN = 2;
-    }
-
-    enum Type {
-        KEYGUARD_INSECURE = 0;
-        KEYGUARD_SECURE = 1;
-        RANDOM_WAKEUP = 2;
-    }
-
-    optional uint64 startTimestampMillis = 1;
-    optional uint64 durationMillis = 2;
-    optional string build = 3;
-    optional Result result = 4;
-    repeated TouchEvent touchEvents = 5;
-    repeated SensorEvent sensorEvents = 6;
-
-    optional int32 touchAreaWidth = 9;
-    optional int32 touchAreaHeight = 10;
-    optional Type type = 11;
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index f7b4994..4837a53 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -59,8 +59,6 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.MultiUserAvatarCache;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.keyguard.analytics.KeyguardAnalytics;
-import com.android.keyguard.analytics.Session;
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.ScrimController;
@@ -70,7 +68,6 @@
 import java.io.File;
 
 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
-import static com.android.keyguard.analytics.KeyguardAnalytics.SessionTypeAdapter;
 
 
 /**
@@ -117,7 +114,6 @@
 public class KeyguardViewMediator extends SystemUI {
     private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
     final static boolean DEBUG = false;
-    private static final boolean ENABLE_ANALYTICS = Build.IS_DEBUGGABLE;
     private final static boolean DBG_WAKE = false;
 
     private final static String TAG = "KeyguardViewMediator";
@@ -199,8 +195,6 @@
 
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
-    private KeyguardAnalytics mKeyguardAnalytics;
-
     // these are protected by synchronized (this)
 
     /**
@@ -469,22 +463,6 @@
                 mViewMediatorCallback, mLockPatternUtils);
         final ContentResolver cr = mContext.getContentResolver();
 
-        if (ENABLE_ANALYTICS && !LockPatternUtils.isSafeModeEnabled() &&
-                Settings.Secure.getInt(cr, KEYGUARD_ANALYTICS_SETTING, 0) == 1) {
-            mKeyguardAnalytics = new KeyguardAnalytics(mContext, new SessionTypeAdapter() {
-
-                @Override
-                public int getSessionType() {
-                    return mLockPatternUtils.isSecure() && !mUpdateMonitor.getUserHasTrust(
-                            mLockPatternUtils.getCurrentUser())
-                            ? Session.TYPE_KEYGUARD_SECURE
-                            : Session.TYPE_KEYGUARD_INSECURE;
-                }
-            }, new File(mContext.getCacheDir(), "keyguard_analytics.bin"));
-        } else {
-            mKeyguardAnalytics = null;
-        }
-
         mScreenOn = mPM.isScreenOn();
 
         mLockSounds = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0);
@@ -585,9 +563,6 @@
             } else {
                 doKeyguardLocked(null);
             }
-            if (ENABLE_ANALYTICS && mKeyguardAnalytics != null) {
-                mKeyguardAnalytics.getCallback().onScreenOff();
-            }
         }
         KeyguardUpdateMonitor.getInstance(mContext).dispatchScreenTurndOff(why);
     }
@@ -830,9 +805,6 @@
                 updateActivityLockScreenState();
                 adjustStatusBarLocked();
             }
-            if (ENABLE_ANALYTICS && mKeyguardAnalytics != null) {
-                mKeyguardAnalytics.getCallback().onSetOccluded(isOccluded);
-            }
         }
     }
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 22ecd33..b2b4217 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -258,17 +258,6 @@
      */
     private NetworkStateTracker mNetTrackers[];
 
-    /**
-     * Holds references to all NetworkAgentInfos claiming to support the legacy
-     * NetworkType.  We used to have a static set of of NetworkStateTrackers
-     * for each network type.  This is the new model.
-     * Supports synchronous inspection of state.
-     * These are built out at startup such that an unsupported network
-     * doesn't get an ArrayList instance, making this a tristate:
-     * unsupported, supported but not active and active.
-     */
-    private ArrayList<NetworkAgentInfo> mNetworkAgentInfoForType[];
-
     /* Handles captive portal check on a network */
     private CaptivePortalTracker mCaptivePortalTracker;
 
@@ -516,6 +505,118 @@
 
     private static final int UID_UNUSED = -1;
 
+    /**
+     * Implements support for the legacy "one network per network type" model.
+     *
+     * We used to have a static array of NetworkStateTrackers, one for each
+     * network type, but that doesn't work any more now that we can have,
+     * for example, more that one wifi network. This class stores all the
+     * NetworkAgentInfo objects that support a given type, but the legacy
+     * API will only see the first one.
+     *
+     * It serves two main purposes:
+     *
+     * 1. Provide information about "the network for a given type" (since this
+     *    API only supports one).
+     * 2. Send legacy connectivity change broadcasts. Broadcasts are sent if
+     *    the first network for a given type changes, or if the default network
+     *    changes.
+     */
+    private class LegacyTypeTracker {
+        /**
+         * Array of lists, one per legacy network type (e.g., TYPE_MOBILE_MMS).
+         * Each list holds references to all NetworkAgentInfos that are used to
+         * satisfy requests for that network type.
+         *
+         * This array is built out at startup such that an unsupported network
+         * doesn't get an ArrayList instance, making this a tristate:
+         * unsupported, supported but not active and active.
+         *
+         * The actual lists are populated when we scan the network types that
+         * are supported on this device.
+         */
+        private ArrayList<NetworkAgentInfo> mTypeLists[];
+
+        public LegacyTypeTracker() {
+            mTypeLists = (ArrayList<NetworkAgentInfo>[])
+                    new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1];
+        }
+
+        public void addSupportedType(int type) {
+            if (mTypeLists[type] != null) {
+                throw new IllegalStateException(
+                        "legacy list for type " + type + "already initialized");
+            }
+            mTypeLists[type] = new ArrayList<NetworkAgentInfo>();
+        }
+
+        private boolean isDefaultNetwork(NetworkAgentInfo nai) {
+            return mNetworkForRequestId.get(mDefaultRequest.requestId) == nai;
+        }
+
+        public boolean isTypeSupported(int type) {
+            return isNetworkTypeValid(type) && mTypeLists[type] != null;
+        }
+
+        public NetworkAgentInfo getNetworkForType(int type) {
+            if (isTypeSupported(type) && !mTypeLists[type].isEmpty()) {
+                return mTypeLists[type].get(0);
+            } else {
+                return null;
+            }
+        }
+
+        public void add(int type, NetworkAgentInfo nai) {
+            if (!isTypeSupported(type)) {
+                return;  // Invalid network type.
+            }
+            if (VDBG) log("Adding agent " + nai + " for legacy network type " + type);
+
+            ArrayList<NetworkAgentInfo> list = mTypeLists[type];
+            if (list.contains(nai)) {
+                loge("Attempting to register duplicate agent for type " + type + ": " + nai);
+                return;
+            }
+
+            if (list.isEmpty() || isDefaultNetwork(nai)) {
+                if (VDBG) log("Sending connected broadcast for type " + type +
+                              "isDefaultNetwork=" + isDefaultNetwork(nai));
+                sendLegacyNetworkBroadcast(nai, true, type);
+            }
+            list.add(nai);
+        }
+
+        public void remove(NetworkAgentInfo nai) {
+            if (VDBG) log("Removing agent " + nai);
+            for (int type = 0; type < mTypeLists.length; type++) {
+                ArrayList<NetworkAgentInfo> list = mTypeLists[type];
+                if (list == null || list.isEmpty()) {
+                    continue;
+                }
+
+                boolean wasFirstNetwork = false;
+                if (list.get(0).equals(nai)) {
+                    // This network was the first in the list. Send broadcast.
+                    wasFirstNetwork = true;
+                }
+                list.remove(nai);
+
+                if (wasFirstNetwork || isDefaultNetwork(nai)) {
+                    if (VDBG) log("Sending disconnected broadcast for type " + type +
+                                  "isDefaultNetwork=" + isDefaultNetwork(nai));
+                    sendLegacyNetworkBroadcast(nai, false, type);
+                }
+
+                if (!list.isEmpty() && wasFirstNetwork) {
+                    if (VDBG) log("Other network available for type " + type +
+                                  ", sending connected broadcast");
+                    sendLegacyNetworkBroadcast(list.get(0), false, type);
+                }
+            }
+        }
+    }
+    private LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker();
+
     public ConnectivityService(Context context, INetworkManagementService netd,
             INetworkStatsService statsService, INetworkPolicyManager policyManager) {
         // Currently, omitting a NetworkFactory will create one internally
@@ -531,7 +632,7 @@
         NetworkCapabilities netCap = new NetworkCapabilities();
         netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
         netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
-        mDefaultRequest = new NetworkRequest(netCap, true, nextNetworkRequestId());
+        mDefaultRequest = new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId());
         NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(),
                 NetworkRequestInfo.REQUEST);
         mNetworkRequests.put(mDefaultRequest, nri);
@@ -587,9 +688,6 @@
         mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_networkTransitionTimeout);
 
-        mNetworkAgentInfoForType = (ArrayList<NetworkAgentInfo>[])
-                new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1];
-
         mNetTrackers = new NetworkStateTracker[
                 ConnectivityManager.MAX_NETWORK_TYPE+1];
         mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1];
@@ -644,7 +742,7 @@
                             "radio " + n.radio + " in network type " + n.type);
                     continue;
                 }
-                mNetworkAgentInfoForType[n.type] = new ArrayList<NetworkAgentInfo>();
+                mLegacyTypeTracker.addSupportedType(n.type);
 
                 mNetConfigs[n.type] = n;
                 mNetworksDefined++;
@@ -3125,11 +3223,9 @@
             } else {
                 loge("Error connecting NetworkAgent");
                 NetworkAgentInfo nai = mNetworkAgentInfos.remove(msg.replyTo);
-                try {
-                    mNetworkAgentInfoForType[nai.networkInfo.getType()].remove(nai);
-                } catch (NullPointerException e) {}
                 if (nai != null) {
                     mNetworkForNetId.remove(nai.network.netId);
+                    mLegacyTypeTracker.remove(nai);
                 }
             }
         }
@@ -3160,10 +3256,7 @@
             nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
             mNetworkAgentInfos.remove(msg.replyTo);
             updateClat(null, nai.linkProperties, nai);
-            try {
-                mNetworkAgentInfoForType[nai.networkInfo.getType()].remove(nai);
-            } catch (NullPointerException e) {}
-
+            mLegacyTypeTracker.remove(nai);
             mNetworkForNetId.remove(nai.network.netId);
             // Since we've lost the network, go through all the requests that
             // it was satisfying and see if any other factory can satisfy them.
@@ -3173,7 +3266,7 @@
                 NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId);
                 if (VDBG) {
                     log(" checking request " + request + ", currentNetwork = " +
-                            currentNetwork != null ? currentNetwork.name() : "null");
+                            (currentNetwork != null ? currentNetwork.name() : "null"));
                 }
                 if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
                     mNetworkForRequestId.remove(request.requestId);
@@ -3223,6 +3316,10 @@
         if (bestNetwork != null) {
             if (VDBG) log("using " + bestNetwork.name());
             bestNetwork.addRequest(nri.request);
+            int legacyType = nri.request.legacyType;
+            if (legacyType != TYPE_NONE) {
+                mLegacyTypeTracker.add(legacyType, bestNetwork);
+            }
             notifyNetworkCallback(bestNetwork, nri);
             score = bestNetwork.currentScore;
         }
@@ -5300,7 +5397,7 @@
 
     @Override
     public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
-            Messenger messenger, int timeoutSec, IBinder binder, boolean legacy) {
+            Messenger messenger, int timeoutSec, IBinder binder, int legacyType) {
         if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
                 == false) {
             enforceConnectivityInternalPermission();
@@ -5312,7 +5409,7 @@
             throw new IllegalArgumentException("Bad timeout specified");
         }
         NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
-                networkCapabilities), legacy, nextNetworkRequestId());
+                networkCapabilities), legacyType, nextNetworkRequestId());
         if (DBG) log("requestNetwork for " + networkRequest);
         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
                 NetworkRequestInfo.REQUEST);
@@ -5338,7 +5435,7 @@
         enforceAccessPermission();
 
         NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
-                networkCapabilities), false, nextNetworkRequestId());
+                networkCapabilities), TYPE_NONE, nextNetworkRequestId());
         if (DBG) log("listenForNetwork for " + networkRequest);
         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
                 NetworkRequestInfo.LISTEN);
@@ -5420,11 +5517,6 @@
     private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
         if (VDBG) log("Got NetworkAgent Messenger");
         mNetworkAgentInfos.put(na.messenger, na);
-        try {
-            mNetworkAgentInfoForType[na.networkInfo.getType()].add(na);
-        } catch (NullPointerException e) {
-            loge("registered NetworkAgent for unsupported type: " + na);
-        }
         mNetworkForNetId.put(na.network.netId, na);
         na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);
         NetworkInfo networkInfo = na.networkInfo;
@@ -5681,6 +5773,10 @@
                     }
                     mNetworkForRequestId.put(nri.request.requestId, newNetwork);
                     newNetwork.addRequest(nri.request);
+                    int legacyType = nri.request.legacyType;
+                    if (legacyType != TYPE_NONE) {
+                        mLegacyTypeTracker.add(legacyType, newNetwork);
+                    }
                     keep = true;
                     // TODO - this could get expensive if we have alot of requests for this
                     // network.  Think about if there is a way to reduce this.  Push
@@ -5694,6 +5790,7 @@
                         } else {
                             setDefaultDnsSystemProperties(new ArrayList<InetAddress>());
                         }
+                        mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
                     }
                 }
             }
@@ -5828,13 +5925,53 @@
 //        } else if (nai.networkMonitor.isEvaluating()) {
 //            notifyType = NetworkCallbacks.callCallbackForRequest(request, nai, notifyType);
 //        }
-        if (nri.request.needsBroadcasts) {
-        // TODO
-//            sendNetworkBroadcast(nai, notifyType);
-        }
         callCallbackForRequest(nri, nai, notifyType);
     }
 
+    private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, boolean connected, int type) {
+        if (connected) {
+            NetworkInfo info = new NetworkInfo(nai.networkInfo);
+            info.setType(type);
+            sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
+        } else {
+            NetworkInfo info = new NetworkInfo(nai.networkInfo);
+            info.setType(type);
+            Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+            intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
+            intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
+            if (info.isFailover()) {
+                intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
+                nai.networkInfo.setFailover(false);
+            }
+            if (info.getReason() != null) {
+                intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
+            }
+            if (info.getExtraInfo() != null) {
+                intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
+            }
+            NetworkAgentInfo newDefaultAgent = null;
+            if (nai.networkRequests.get(mDefaultRequest.requestId) != null) {
+                newDefaultAgent = mNetworkForRequestId.get(mDefaultRequest.requestId);
+                if (newDefaultAgent != null) {
+                    intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO,
+                            newDefaultAgent.networkInfo);
+                } else {
+                    intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
+                }
+            }
+            intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION,
+                    mDefaultInetConditionPublished);
+            final Intent immediateIntent = new Intent(intent);
+            immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
+            sendStickyBroadcast(immediateIntent);
+            sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
+            if (newDefaultAgent != null) {
+                sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo,
+                getConnectivityChangeDelay());
+            }
+        }
+    }
+
     protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType) {
         if (VDBG) log("notifyType " + notifyType + " for " + networkAgent.name());
         for (int i = 0; i < networkAgent.networkRequests.size(); i++) {
@@ -5843,76 +5980,33 @@
             if (VDBG) log(" sending notification for " + nr);
             callCallbackForRequest(nri, networkAgent, notifyType);
         }
-        if (networkAgent.needsBroadcasts) {
-            if (notifyType == ConnectivityManager.CALLBACK_AVAILABLE) {
-                sendConnectedBroadcastDelayed(networkAgent.networkInfo,
-                        getConnectivityChangeDelay());
-            } else if (notifyType == ConnectivityManager.CALLBACK_LOST) {
-                NetworkInfo info = new NetworkInfo(networkAgent.networkInfo);
-                Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
-                intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
-                intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
-                if (info.isFailover()) {
-                    intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
-                    networkAgent.networkInfo.setFailover(false);
-                }
-                if (info.getReason() != null) {
-                    intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
-                }
-                if (info.getExtraInfo() != null) {
-                    intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
-                }
-                NetworkAgentInfo newDefaultAgent = null;
-                if (networkAgent.networkRequests.get(mDefaultRequest.requestId) != null) {
-                    newDefaultAgent = mNetworkForRequestId.get(mDefaultRequest.requestId);
-                    if (newDefaultAgent != null) {
-                        intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO,
-                                newDefaultAgent.networkInfo);
-                    } else {
-                        intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
-                    }
-                }
-                intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION,
-                        mDefaultInetConditionPublished);
-                final Intent immediateIntent = new Intent(intent);
-                immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
-                sendStickyBroadcast(immediateIntent);
-                sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
-                if (newDefaultAgent != null) {
-                    sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo,
-                            getConnectivityChangeDelay());
-                }
-            }
-        }
     }
 
     private LinkProperties getLinkPropertiesForTypeInternal(int networkType) {
-        ArrayList<NetworkAgentInfo> list = mNetworkAgentInfoForType[networkType];
-        if (list == null) return null;
-        try {
-            return new LinkProperties(list.get(0).linkProperties);
-        } catch (IndexOutOfBoundsException e) {
-            return new LinkProperties();
-        }
+        NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
+        return (nai != null) ?
+                new LinkProperties(nai.linkProperties) :
+                new LinkProperties();
     }
 
     private NetworkInfo getNetworkInfoForType(int networkType) {
-        ArrayList<NetworkAgentInfo> list = mNetworkAgentInfoForType[networkType];
-        if (list == null) return null;
-        try {
-            return new NetworkInfo(list.get(0).networkInfo);
-        } catch (IndexOutOfBoundsException e) {
-            return new NetworkInfo(networkType, 0, "Unknown", "");
+        if (!mLegacyTypeTracker.isTypeSupported(networkType))
+            return null;
+
+        NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
+        if (nai != null) {
+            NetworkInfo result = new NetworkInfo(nai.networkInfo);
+            result.setType(networkType);
+            return result;
+        } else {
+           return new NetworkInfo(networkType, 0, "Unknown", "");
         }
     }
 
     private NetworkCapabilities getNetworkCapabilitiesForType(int networkType) {
-        ArrayList<NetworkAgentInfo> list = mNetworkAgentInfoForType[networkType];
-        if (list == null) return null;
-        try {
-            return new NetworkCapabilities(list.get(0).networkCapabilities);
-        } catch (IndexOutOfBoundsException e) {
-            return new NetworkCapabilities();
-        }
+        NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
+        return (nai != null) ?
+                new NetworkCapabilities(nai.networkCapabilities) :
+                new NetworkCapabilities();
     }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 61ba6e0..aede797 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2978,6 +2978,10 @@
                 }
             }
             buf.append("}");
+            if (requiredAbi != null) {
+                buf.append(" abi=");
+                buf.append(requiredAbi);
+            }
             Slog.i(TAG, buf.toString());
             app.setPid(startResult.pid);
             app.usingWrapper = startResult.usingWrapper;
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index e9f9683..b03c247 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -45,18 +45,6 @@
     public int currentScore;
     public final NetworkMonitor networkMonitor;
 
-    /**
-     * Indicates we need to send CONNECTIVITY_ACTION broadcasts for this network.
-     * For example the built-in default network request and any requsts coming from
-     * the deprecated startUsingNetworkFeature API will have this set.  Networks
-     * responding to the new requestNetwork API will rely on point to point callbacks.
-     *
-     * Gets set if any legacy requests get affiliated with this network and
-     * stays set for life so we send disconnected bcasts to match the connected,
-     * even if the legacy request has moved on.
-     */
-    public boolean needsBroadcasts = false;
-
     // The list of NetworkRequests being satisfied by this Network.
     public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>();
     public final ArrayList<NetworkRequest> networkLingered = new ArrayList<NetworkRequest>();
@@ -78,8 +66,6 @@
     }
 
     public void addRequest(NetworkRequest networkRequest) {
-        if (networkRequest.needsBroadcasts) needsBroadcasts = true;
-
         networkRequests.put(networkRequest.requestId, networkRequest);
     }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index d0b716d..5141d16 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -505,7 +505,7 @@
             // Reply <Feature Abort> to initiator (source) for all requests.
             HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand(
                     sourceAddress, message.getSource(), message.getOpcode(),
-                    HdmiCecMessageBuilder.ABORT_REFUSED);
+                    HdmiConstants.ABORT_REFUSED);
             sendCommand(cecMessage, null);
         }
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 9a76734..6c2be34 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -26,15 +26,6 @@
  * A helper class to build {@link HdmiCecMessage} from various cec commands.
  */
 public class HdmiCecMessageBuilder {
-    // TODO: move these values to HdmiCec.java once make it internal constant class.
-    // CEC's ABORT reason values.
-    static final int ABORT_UNRECOGNIZED_MODE = 0;
-    static final int ABORT_NOT_IN_CORRECT_MODE = 1;
-    static final int ABORT_CANNOT_PROVIDE_SOURCE = 2;
-    static final int ABORT_INVALID_OPERAND = 3;
-    static final int ABORT_REFUSED = 4;
-    static final int ABORT_UNABLE_TO_DETERMINE = 5;
-
     private static final int OSD_NAME_MAX_LENGTH = 13;
 
     private HdmiCecMessageBuilder() {}
@@ -290,6 +281,64 @@
     }
 
     /**
+     * Build &lt;System Audio Mode Request&gt; command.
+     *
+     * @param src source address of command
+     * @param avr destination address of command, it should be AVR
+     * @param avrPhysicalAddress physical address of AVR
+     * @param enableSystemAudio whether to enable System Audio Mode or not
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildSystemAudioModeRequest(int src, int avr, int avrPhysicalAddress,
+            boolean enableSystemAudio) {
+        if (enableSystemAudio) {
+            return buildCommand(src, avr, HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST,
+                    physicalAddressToParam(avrPhysicalAddress));
+        } else {
+            return buildCommand(src, avr, HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST);
+        }
+    }
+
+    /**
+     * Build &lt;Give Audio Status&gt; command.
+     *
+     * @param src source address of command
+     * @param dest destination address of command
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildGiveAudioStatus(int src, int dest) {
+        return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_AUDIO_STATUS);
+    }
+
+    /**
+     * Build &lt;User Control Pressed&gt; command.
+     *
+     * @param src source address of command
+     * @param dest destination address of command
+     * @param uiCommand keycode that user pressed
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildUserControlPressed(int src, int dest, int uiCommand) {
+        byte[] params = new byte[] {
+                (byte) uiCommand
+        };
+        return buildCommand(src, dest, HdmiCec.MESSAGE_USER_CONTROL_PRESSED, params);
+    }
+
+    /**
+     * Build &lt;User Control Released&gt; command.
+     *
+     * @param src source address of command
+     * @param dest destination address of command
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildUserControlReleased(int src, int dest) {
+        return buildCommand(src, dest, HdmiCec.MESSAGE_USER_CONTROL_RELEASED);
+    }
+
+    /***** Please ADD new buildXXX() methods above. ******/
+
+    /**
      * Build a {@link HdmiCecMessage} without extra parameter.
      *
      * @param src source address of command
diff --git a/services/core/java/com/android/server/hdmi/HdmiConstants.java b/services/core/java/com/android/server/hdmi/HdmiConstants.java
new file mode 100644
index 0000000..a83d1ed
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiConstants.java
@@ -0,0 +1,47 @@
+/*
+ * 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.hdmi;
+
+/**
+ * Defines constants related to HDMI-CEC protocol internal implementation.
+ * If a constant will be used in the public api, it should be located in
+ * {@link android.hardware.hdmi.HdmiCec}.
+ */
+final class HdmiConstants {
+
+    // Constants related to operands of HDMI CEC commands.
+    // Refer to CEC Table 29 in HDMI Spec v1.4b.
+    // [Abort Reason]
+    static final int ABORT_UNRECOGNIZED_MODE = 0;
+    static final int ABORT_NOT_IN_CORRECT_MODE = 1;
+    static final int ABORT_CANNOT_PROVIDE_SOURCE = 2;
+    static final int ABORT_INVALID_OPERAND = 3;
+    static final int ABORT_REFUSED = 4;
+    static final int ABORT_UNABLE_TO_DETERMINE = 5;
+
+    // [Audio Status]
+    static final int SYSTEM_AUDIO_STATUS_OFF = 0;
+    static final int SYSTEM_AUDIO_STATUS_ON = 1;
+
+    // Constants related to UI Command Codes.
+    // Refer to CEC Table 30 in HDMI Spec v1.4b.
+    static final int UI_COMMAND_MUTE = 0x43;
+    static final int UI_COMMAND_MUTE_FUNCTION = 0x65;
+    static final int UI_COMMAND_RESTORE_VOLUME_FUNCTION = 0x66;
+
+    private HdmiConstants() { /* cannot be instantiated */ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index d775733..0f3fc21 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -118,8 +118,11 @@
     // TODO: it may need to hold lock if it's accessed from others.
     private boolean mArcStatusEnabled = false;
 
+    // Whether SystemAudioMode is "On" or not.
+    private boolean mSystemAudioMode;
+
     // Handler running on service thread. It's used to run a task in service thread.
-    private Handler mHandler = new Handler();
+    private final Handler mHandler = new Handler();
 
     public HdmiControlService(Context context) {
         super(context);
@@ -158,6 +161,9 @@
         }
 
         publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService());
+
+        // TODO: Read the preference for SystemAudioMode and initialize mSystemAudioMode and
+        // start to monitor the preference value and invoke SystemAudioActionFromTv if needed.
     }
 
     /**
@@ -211,35 +217,43 @@
      * @param action {@link FeatureAction} to remove
      */
     void removeAction(final FeatureAction action) {
-        runOnServiceThread(new Runnable() {
-            @Override
-            public void run() {
-                mActions.remove(action);
-            }
-        });
+        assertRunOnServiceThread();
+        mActions.remove(action);
     }
 
     // Remove all actions matched with the given Class type.
     private <T extends FeatureAction> void removeAction(final Class<T> clazz) {
-        runOnServiceThread(new Runnable() {
-            @Override
-            public void run() {
-                Iterator<FeatureAction> iter = mActions.iterator();
-                while (iter.hasNext()) {
-                    FeatureAction action = iter.next();
-                    if (action.getClass().equals(clazz)) {
-                        action.clear();
-                        mActions.remove(action);
-                    }
-                }
+        removeActionExcept(clazz, null);
+    }
+
+    // Remove all actions matched with the given Class type besides |exception|.
+    <T extends FeatureAction> void removeActionExcept(final Class<T> clazz,
+            final FeatureAction exception) {
+        assertRunOnServiceThread();
+        Iterator<FeatureAction> iter = mActions.iterator();
+        while (iter.hasNext()) {
+            FeatureAction action = iter.next();
+            if (action != exception && action.getClass().equals(clazz)) {
+                action.clear();
+                mActions.remove(action);
             }
-        });
+        }
     }
 
     private void runOnServiceThread(Runnable runnable) {
         mHandler.post(runnable);
     }
 
+    void runOnServiceThreadAtFrontOfQueue(Runnable runnable) {
+        mHandler.postAtFrontOfQueue(runnable);
+    }
+
+    private void assertRunOnServiceThread() {
+        if (Looper.myLooper() != mHandler.getLooper()) {
+            throw new IllegalStateException("Should run on service thread.");
+        }
+    }
+
     /**
      * Change ARC status into the given {@code enabled} status.
      *
@@ -306,8 +320,12 @@
             case HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS:
                 handleReportPhysicalAddress(message);
                 return true;
-            // TODO: Add remaining system information query such as
-            // <Give Device Power Status> and <Request Active Source> handler.
+            case HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE:
+                handleSetSystemAudioMode(message);
+                return true;
+            case HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_STATUS:
+                handleSystemAudioModeStatus(message);
+                return true;
             default:
                 return dispatchMessageToAction(message);
         }
@@ -413,7 +431,7 @@
             sendCecCommand(
                     HdmiCecMessageBuilder.buildFeatureAbortCommand(message.getDestination(),
                             message.getSource(), HdmiCec.MESSAGE_GET_MENU_LANGUAGE,
-                            HdmiCecMessageBuilder.ABORT_UNRECOGNIZED_MODE));
+                            HdmiConstants.ABORT_UNRECOGNIZED_MODE));
             return;
         }
 
@@ -438,6 +456,33 @@
         return false;
     }
 
+    private void handleSetSystemAudioMode(HdmiCecMessage message) {
+        if (dispatchMessageToAction(message) || !isMessageForSystemAudio(message)) {
+            return;
+        }
+        SystemAudioActionFromAvr action = new SystemAudioActionFromAvr(this,
+                message.getDestination(), message.getSource(),
+                HdmiUtils.parseCommandParamSystemAudioStatus(message));
+        addAndStartAction(action);
+    }
+
+    private void handleSystemAudioModeStatus(HdmiCecMessage message) {
+        if (!isMessageForSystemAudio(message)) {
+            return;
+        }
+        setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message));
+    }
+
+    private boolean isMessageForSystemAudio(HdmiCecMessage message) {
+        if (message.getSource() != HdmiCec.ADDR_AUDIO_SYSTEM
+                || message.getDestination() != HdmiCec.ADDR_TV
+                || getAvrDeviceInfo() == null) {
+            Slog.w(TAG, "Skip abnormal CecMessage: " + message);
+            return false;
+        }
+        return true;
+    }
+
     // Record class that monitors the event of the caller of being killed. Used to clean up
     // the listener list and record list accordingly.
     private final class HotplugEventListenerRecord implements IBinder.DeathRecipient {
@@ -627,4 +672,32 @@
             Slog.e(TAG, "Invoking callback failed:" + e);
         }
     }
+
+    HdmiCecDeviceInfo getAvrDeviceInfo() {
+        return mCecController.getDeviceInfo(HdmiCec.ADDR_AUDIO_SYSTEM);
+    }
+
+    void setSystemAudioMode(boolean newMode) {
+        assertRunOnServiceThread();
+        if (newMode != mSystemAudioMode) {
+            // TODO: Need to set the preference for SystemAudioMode.
+            // TODO: Need to handle the notification of changing the mode and
+            // to identify the notification should be handled in the service or TvSettings.
+            mSystemAudioMode = newMode;
+        }
+    }
+
+    boolean getSystemAudioMode() {
+        assertRunOnServiceThread();
+        return mSystemAudioMode;
+    }
+
+    void setAudioStatus(boolean mute, int volume) {
+        // TODO: Hook up with AudioManager.
+    }
+
+    boolean isInPresetInstallationMode() {
+        // TODO: Implement this.
+        return false;
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
new file mode 100644
index 0000000..ef128ed1
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -0,0 +1,74 @@
+/*
+ * 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.hdmi;
+
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.util.Slog;
+
+/**
+ * Various utilities to handle HDMI CEC messages.
+ */
+final class HdmiUtils {
+
+    private HdmiUtils() { /* cannot be instantiated */ }
+
+    /**
+     * Verify if the given address is for the given device type.  If not it will throw
+     * {@link IllegalArgumentException}.
+     *
+     * @param logicalAddress the logical address to verify
+     * @param deviceType the device type to check
+     * @throw IllegalArgumentException
+     */
+    static void verifyAddressType(int logicalAddress, int deviceType) {
+        int actualDeviceType = HdmiCec.getTypeFromAddress(logicalAddress);
+        if (actualDeviceType != deviceType) {
+            throw new IllegalArgumentException("Device type missmatch:[Expected:" + deviceType
+                    + ", Actual:" + actualDeviceType);
+        }
+    }
+
+    /**
+     * Check if the given CEC message come from the given address.
+     *
+     * @param cmd the CEC message to check
+     * @param expectedAddress the expected source address of the given message
+     * @param tag the tag of caller module (for log message)
+     * @return true if the CEC message comes from the given address
+     */
+    static boolean checkCommandSource(HdmiCecMessage cmd, int expectedAddress, String tag) {
+        int src = cmd.getSource();
+        if (src != expectedAddress) {
+            Slog.w(tag, "Invalid source [Expected:" + expectedAddress + ", Actual:" + src + "]");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Parse the parameter block of CEC message as [System Audio Status].
+     *
+     * @param cmd the CEC message to parse
+     * @return true if the given parameter has [ON] value
+     */
+    static boolean parseCommandParamSystemAudioStatus(HdmiCecMessage cmd) {
+        // TODO: Handle the exception when the length is wrong.
+        return cmd.getParams().length > 0
+                && cmd.getParams()[0] == HdmiConstants.SYSTEM_AUDIO_STATUS_ON;
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/RequestArcAction.java b/services/core/java/com/android/server/hdmi/RequestArcAction.java
index 05614a4..08ca306 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcAction.java
@@ -44,28 +44,15 @@
      */
     RequestArcAction(HdmiControlService service, int sourceAddress, int avrAddress) {
         super(service, sourceAddress);
-        verifyAddressType(sourceAddress, HdmiCec.DEVICE_TV);
-        verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
+        HdmiUtils.verifyAddressType(sourceAddress, HdmiCec.DEVICE_TV);
+        HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
         mAvrAddress = avrAddress;
     }
 
-    private static void verifyAddressType(int logicalAddress, int deviceType) {
-        int actualDeviceType = HdmiCec.getTypeFromAddress(logicalAddress);
-        if (actualDeviceType != deviceType) {
-            throw new IllegalArgumentException("Device type missmatch:[Expected:" + deviceType
-                    + ", Actual:" + actualDeviceType);
-        }
-    }
-
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
-        if (mState != STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE) {
-            return false;
-        }
-
-        int src = cmd.getSource();
-        if (src != mAvrAddress) {
-            Slog.w(TAG, "Invalid source [Expected:" + mAvrAddress + ", Actual:" + src + "]");
+        if (mState != STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE
+                || !HdmiUtils.checkCommandSource(cmd, mAvrAddress, TAG)) {
             return false;
         }
         int opcode = cmd.getOpcode();
diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
index e3525d8..d53d88d 100644
--- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
+++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
@@ -46,21 +46,12 @@
     SetArcTransmissionStateAction(HdmiControlService service, int sourceAddress, int avrAddress,
             boolean enabled) {
         super(service, sourceAddress);
-        verifyAddressType(sourceAddress, HdmiCec.DEVICE_TV);
-        verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
+        HdmiUtils.verifyAddressType(sourceAddress, HdmiCec.DEVICE_TV);
+        HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
         mAvrAddress = avrAddress;
         mEnabled = enabled;
     }
 
-    // TODO: extract it as separate utility class.
-    private static void verifyAddressType(int logicalAddress, int deviceType) {
-        int actualDeviceType = HdmiCec.getTypeFromAddress(logicalAddress);
-        if (actualDeviceType != deviceType) {
-            throw new IllegalArgumentException("Device type missmatch:[Expected:" + deviceType
-                    + ", Actual:" + actualDeviceType);
-        }
-    }
-
     @Override
     boolean start() {
         if (mEnabled) {
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
new file mode 100644
index 0000000..dde3342
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
@@ -0,0 +1,192 @@
+/*
+ * 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.hdmi;
+
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecMessage;
+
+/**
+ * Base feature action class for SystemAudioActionFromTv and SystemAudioActionFromAvr.
+ */
+abstract class SystemAudioAction extends FeatureAction {
+    private static final String TAG = "SystemAudioAction";
+
+    // State in which waits for <SetSystemAudioMode>.
+    private static final int STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE = 1;
+
+    // State in which waits for <ReportAudioStatus>.
+    private static final int STATE_WAIT_FOR_REPORT_AUDIO_STATUS = 2;
+
+    private static final int MAX_SEND_RETRY_COUNT = 2;
+
+    private static final int ON_TIMEOUT_MS = 5000;
+    private static final int OFF_TIMEOUT_MS = TIMEOUT_MS;
+
+    // Logical address of AV Receiver.
+    protected final int mAvrLogicalAddress;
+
+    // The target audio status of the action, whether to enable the system audio mode or not.
+    protected boolean mTargetAudioStatus;
+
+    private int mSendRetryCount = 0;
+
+    /**
+     * Constructor
+     *
+     * @param service {@link HdmiControlService} instance
+     * @param sourceAddress logical address of source device (TV or STB).
+     * @param avrAddress logical address of AVR device
+     * @param targetStatus Whether to enable the system audio mode or not
+     * @throw IllegalArugmentException if device type of sourceAddress and avrAddress is invalid
+     */
+    SystemAudioAction(HdmiControlService service, int sourceAddress, int avrAddress,
+            boolean targetStatus) {
+        super(service, sourceAddress);
+        HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
+        mAvrLogicalAddress = avrAddress;
+        mTargetAudioStatus = targetStatus;
+    }
+
+    protected void sendSystemAudioModeRequest() {
+        int avrPhysicalAddress = mService.getAvrDeviceInfo().getPhysicalAddress();
+        HdmiCecMessage command = HdmiCecMessageBuilder.buildSystemAudioModeRequest(mSourceAddress,
+                mAvrLogicalAddress, avrPhysicalAddress, mTargetAudioStatus);
+        sendCommand(command, new HdmiControlService.SendMessageCallback() {
+            @Override
+            public void onSendCompleted(int error) {
+                if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
+                    mState = STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE;
+                    addTimer(mState, mTargetAudioStatus ? ON_TIMEOUT_MS : OFF_TIMEOUT_MS);
+                } else {
+                    setSystemAudioMode(false);
+                    finish();
+                }
+            }
+        });
+    }
+
+    private void handleSendSystemAudioModeRequestTimeout() {
+        if (!mTargetAudioStatus  // Don't retry for Off case.
+                || mSendRetryCount++ >= MAX_SEND_RETRY_COUNT) {
+            setSystemAudioMode(false);
+            finish();
+            return;
+        }
+        sendSystemAudioModeRequest();
+    }
+
+    protected void setSystemAudioMode(boolean mode) {
+        mService.setSystemAudioMode(mode);
+    }
+
+    protected void sendGiveAudioStatus() {
+        HdmiCecMessage command = HdmiCecMessageBuilder.buildGiveAudioStatus(mSourceAddress,
+                mAvrLogicalAddress);
+        sendCommand(command, new HdmiControlService.SendMessageCallback() {
+            @Override
+            public void onSendCompleted(int error) {
+                if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
+                    mState = STATE_WAIT_FOR_REPORT_AUDIO_STATUS;
+                    addTimer(mState, TIMEOUT_MS);
+                } else {
+                    handleSendGiveAudioStatusFailure();
+                }
+            }
+        });
+    }
+
+    private void handleSendGiveAudioStatusFailure() {
+        // TODO: Notify the failure status.
+
+        int uiCommand = mService.getSystemAudioMode()
+                ? HdmiConstants.UI_COMMAND_RESTORE_VOLUME_FUNCTION  // SystemAudioMode: ON
+                : HdmiConstants.UI_COMMAND_MUTE_FUNCTION;           // SystemAudioMode: OFF
+        sendUserControlPressedAndReleased(uiCommand);
+        finish();
+    }
+
+    private void sendUserControlPressedAndReleased(int uiCommand) {
+        sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(
+                mSourceAddress, mAvrLogicalAddress, uiCommand));
+        sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
+                mSourceAddress, mAvrLogicalAddress));
+    }
+
+    @Override
+    final boolean processCommand(HdmiCecMessage cmd) {
+        switch (mState) {
+            case STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE:
+                // TODO: Handle <FeatureAbort> of <SystemAudioModeRequest>
+                if (cmd.getOpcode() != HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE
+                        || !HdmiUtils.checkCommandSource(cmd, mAvrLogicalAddress, TAG)) {
+                    return false;
+                }
+                boolean receivedStatus = HdmiUtils.parseCommandParamSystemAudioStatus(cmd);
+                if (receivedStatus == mTargetAudioStatus) {
+                    setSystemAudioMode(receivedStatus);
+                    sendGiveAudioStatus();
+                } else {
+                    // Unexpected response, consider the request is newly initiated by AVR.
+                    // To return 'false' will initiate new SystemAudioActionFromAvr by the control
+                    // service.
+                    finish();
+                    return false;
+                }
+                return true;
+
+            case STATE_WAIT_FOR_REPORT_AUDIO_STATUS:
+                // TODO: Handle <FeatureAbort> of <GiveAudioStatus>
+                if (cmd.getOpcode() != HdmiCec.MESSAGE_REPORT_AUDIO_STATUS
+                        || !HdmiUtils.checkCommandSource(cmd, mAvrLogicalAddress, TAG)) {
+                    return false;
+                }
+                byte[] params = cmd.getParams();
+                if (params.length > 0) {
+                    boolean mute = (params[0] & 0x80) == 0x80;
+                    int volume = params[0] & 0x7F;
+                    mService.setAudioStatus(mute, volume);
+                    if (mTargetAudioStatus && mute || !mTargetAudioStatus && !mute) {
+                        // Toggle AVR's mute status to match with the system audio status.
+                        sendUserControlPressedAndReleased(HdmiConstants.UI_COMMAND_MUTE);
+                    }
+                }
+                finish();
+                return true;
+        }
+        return false;
+    }
+
+    protected void removeSystemAudioActionInProgress() {
+        mService.removeActionExcept(SystemAudioActionFromTv.class, this);
+        mService.removeActionExcept(SystemAudioActionFromAvr.class, this);
+    }
+
+    @Override
+    final void handleTimerEvent(int state) {
+        if (mState != state) {
+            return;
+        }
+        switch (mState) {
+            case STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE:
+                handleSendSystemAudioModeRequestTimeout();
+                return;
+            case STATE_WAIT_FOR_REPORT_AUDIO_STATUS:
+                handleSendGiveAudioStatusFailure();
+                return;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
new file mode 100644
index 0000000..c5eb44b
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
@@ -0,0 +1,69 @@
+/*
+ * 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.hdmi;
+
+import android.hardware.hdmi.HdmiCec;
+
+/**
+ * Feature action that handles System Audio initiated by AVR devices.
+ */
+final class SystemAudioActionFromAvr extends SystemAudioAction {
+    /**
+     * Constructor
+     *
+     * @param service {@link HdmiControlService} instance
+     * @param tvAddress logical address of TV device
+     * @param avrAddress logical address of AVR device
+     * @param targetStatus Whether to enable the system audio mode or not
+     * @throw IllegalArugmentException if device type of tvAddress and avrAddress is invalid
+     */
+    SystemAudioActionFromAvr(HdmiControlService service, int tvAddress, int avrAddress,
+            boolean targetStatus) {
+        super(service, tvAddress, avrAddress, targetStatus);
+        HdmiUtils.verifyAddressType(tvAddress, HdmiCec.DEVICE_TV);
+    }
+
+    @Override
+    boolean start() {
+        removeSystemAudioActionInProgress();
+        handleSystemAudioActionFromAvr();
+        return true;
+    }
+
+    private void handleSystemAudioActionFromAvr() {
+        if (mTargetAudioStatus == mService.getSystemAudioMode()) {
+            finish();
+            return;
+        }
+        if (mService.isInPresetInstallationMode()) {
+            sendCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(
+                    mSourceAddress, mAvrLogicalAddress,
+                    HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE, HdmiConstants.ABORT_REFUSED));
+            mTargetAudioStatus = false;
+            sendSystemAudioModeRequest();
+            return;
+        }
+        // TODO: Stop the action for System Audio Mode initialization if it is running.
+        if (mTargetAudioStatus) {
+            setSystemAudioMode(true);
+            sendGiveAudioStatus();
+        } else {
+            setSystemAudioMode(false);
+            finish();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
new file mode 100644
index 0000000..9994de6
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
@@ -0,0 +1,50 @@
+/*
+ * 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.hdmi;
+
+import android.hardware.hdmi.HdmiCec;
+
+
+/**
+ * Feature action that handles System Audio initiated by TV devices.
+ */
+final class SystemAudioActionFromTv extends SystemAudioAction {
+    /**
+     * Constructor
+     *
+     * @param service {@link HdmiControlService} instance
+     * @param tvAddress logical address of TV device
+     * @param avrAddress logical address of AVR device
+     * @param targetStatus Whether to enable the system audio mode or not
+     * @throw IllegalArugmentException if device type of tvAddress is invalid
+     */
+    SystemAudioActionFromTv(HdmiControlService service, int tvAddress, int avrAddress,
+            boolean targetStatus) {
+        super(service, tvAddress, avrAddress, targetStatus);
+        HdmiUtils.verifyAddressType(tvAddress, HdmiCec.DEVICE_TV);
+    }
+
+    @Override
+    boolean start() {
+        // TODO: Check HDMI-CEC is enabled.
+        // TODO: Move to the waiting state if currently a routing change is in progress.
+
+        removeSystemAudioActionInProgress();
+        sendSystemAudioModeRequest();
+        return true;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 13cc98c..bb93663 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -40,6 +40,7 @@
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.content.NativeLibraryHelper.ApkHandle;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FastXmlSerializer;
@@ -4148,7 +4149,7 @@
                 continue;
             }
             PackageParser.Package pkg = scanPackageLI(file,
-                    flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null);
+                    flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null, null);
             // Don't mess around with apps in system partition.
             if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                     mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
@@ -4215,7 +4216,7 @@
      *  Returns null in case of errors and the error code is stored in mLastScanError
      */
     private PackageParser.Package scanPackageLI(File scanFile,
-            int parseFlags, int scanMode, long currentTime, UserHandle user) {
+            int parseFlags, int scanMode, long currentTime, UserHandle user, String abiOverride) {
         mLastScanError = PackageManager.INSTALL_SUCCEEDED;
         String scanPath = scanFile.getPath();
         if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanPath);
@@ -4283,7 +4284,7 @@
                     mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
                     return null;
                 } else {
-                    // The current app on the system partion is better than
+                    // The current app on the system partition is better than
                     // what we have updated to on the data partition; switch
                     // back to the system partition version.
                     // At this point, its safely assumed that package installation for
@@ -4402,7 +4403,7 @@
         setApplicationInfoPaths(pkg, codePath, resPath);
         // Note that we invoke the following method only if we are about to unpack an application
         PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode
-                | SCAN_UPDATE_SIGNATURE, currentTime, user);
+                | SCAN_UPDATE_SIGNATURE, currentTime, user, abiOverride);
 
         /*
          * If the system app should be overridden by a previously installed
@@ -4945,7 +4946,7 @@
     }
 
     private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
-            int parseFlags, int scanMode, long currentTime, UserHandle user) {
+            int parseFlags, int scanMode, long currentTime, UserHandle user, String abiOverride) {
         File scanFile = new File(pkg.mScanPath);
         if (scanFile == null || pkg.applicationInfo.sourceDir == null ||
                 pkg.applicationInfo.publicSourceDir == null) {
@@ -5395,7 +5396,22 @@
          *        only for non-system apps and system app upgrades.
          */
         if (pkg.applicationInfo.nativeLibraryDir != null) {
+            final NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(scanFile);
             try {
+                // Enable gross and lame hacks for apps that are built with old
+                // SDK tools. We must scan their APKs for renderscript bitcode and
+                // not launch them if it's present. Don't bother checking on devices
+                // that don't have 64 bit support.
+                String[] abiList = Build.SUPPORTED_ABIS;
+                boolean hasLegacyRenderscriptBitcode = false;
+                if (abiOverride != null) {
+                    abiList = new String[] { abiOverride };
+                } else if (Build.SUPPORTED_64_BIT_ABIS.length > 0 &&
+                        NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
+                    abiList = Build.SUPPORTED_32_BIT_ABIS;
+                    hasLegacyRenderscriptBitcode = true;
+                }
+
                 File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
                 final String dataPathString = dataPath.getCanonicalPath();
 
@@ -5411,21 +5427,26 @@
                         Log.i(TAG, "removed obsolete native libraries for system package "
                                 + path);
                     }
-
-                    setInternalAppAbi(pkg, pkgSetting);
+                    if (abiOverride != null || hasLegacyRenderscriptBitcode) {
+                        pkg.applicationInfo.cpuAbi = abiList[0];
+                        pkgSetting.cpuAbiString = abiList[0];
+                    } else {
+                        setInternalAppAbi(pkg, pkgSetting);
+                    }
                 } else {
                     if (!isForwardLocked(pkg) && !isExternal(pkg)) {
                         /*
-                         * Update native library dir if it starts with
-                         * /data/data
-                         */
+                        * Update native library dir if it starts with
+                        * /data/data
+                        */
                         if (nativeLibraryDir.getPath().startsWith(dataPathString)) {
                             setInternalAppNativeLibraryPath(pkg, pkgSetting);
                             nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
                         }
 
                         try {
-                            int copyRet = copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir);
+                            int copyRet = copyNativeLibrariesForInternalApp(handle,
+                                    nativeLibraryDir, abiList);
                             if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
                                 Slog.e(TAG, "Unable to copy native libraries");
                                 mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
@@ -5435,7 +5456,9 @@
                             // We've successfully copied native libraries across, so we make a
                             // note of what ABI we're using
                             if (copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
-                                pkg.applicationInfo.cpuAbi = Build.SUPPORTED_ABIS[copyRet];
+                                pkg.applicationInfo.cpuAbi = abiList[copyRet];
+                            } else if (abiOverride != null || hasLegacyRenderscriptBitcode) {
+                                pkg.applicationInfo.cpuAbi = abiList[0];
                             } else {
                                 pkg.applicationInfo.cpuAbi = null;
                             }
@@ -5452,20 +5475,22 @@
                         // to clean this up but we'll need to change the interface between this service
                         // and IMediaContainerService (but doing so will spread this logic out, rather
                         // than centralizing it).
-                        final NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(scanFile);
-                        final int abi = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_ABIS);
+                        final int abi = NativeLibraryHelper.findSupportedAbi(handle, abiList);
                         if (abi >= 0) {
-                            pkg.applicationInfo.cpuAbi = Build.SUPPORTED_ABIS[abi];
+                            pkg.applicationInfo.cpuAbi = abiList[abi];
                         } else if (abi == PackageManager.NO_NATIVE_LIBRARIES) {
                             // Note that (non upgraded) system apps will not have any native
                             // libraries bundled in their APK, but we're guaranteed not to be
                             // such an app at this point.
-                            pkg.applicationInfo.cpuAbi = null;
+                            if (abiOverride != null || hasLegacyRenderscriptBitcode) {
+                                pkg.applicationInfo.cpuAbi = abiList[0];
+                            } else {
+                                pkg.applicationInfo.cpuAbi = null;
+                            }
                         } else {
                             mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
                             return null;
                         }
-                        handle.close();
                     }
 
                     if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path);
@@ -5482,8 +5507,12 @@
                         }
                     }
                 }
+
+                pkgSetting.cpuAbiString = pkg.applicationInfo.cpuAbi;
             } catch (IOException ioe) {
                 Slog.e(TAG, "Unable to get canonical file " + ioe.toString());
+            } finally {
+                handle.close();
             }
         }
         pkg.mScanPath = path;
@@ -6175,8 +6204,8 @@
         }
     }
 
-    private static int copyNativeLibrariesForInternalApp(File scanFile, final File nativeLibraryDir)
-            throws IOException {
+    private static int copyNativeLibrariesForInternalApp(ApkHandle handle,
+            final File nativeLibraryDir, String[] abiList) throws IOException {
         if (!nativeLibraryDir.isDirectory()) {
             nativeLibraryDir.delete();
 
@@ -6198,21 +6227,16 @@
          * If this is an internal application or our nativeLibraryPath points to
          * the app-lib directory, unpack the libraries if necessary.
          */
-        final NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(scanFile);
-        try {
-            int abi = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_ABIS);
-            if (abi >= 0) {
-                int copyRet = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle,
-                        nativeLibraryDir, Build.SUPPORTED_ABIS[abi]);
-                if (copyRet != PackageManager.INSTALL_SUCCEEDED) {
-                    return copyRet;
-                }
+        int abi = NativeLibraryHelper.findSupportedAbi(handle, abiList);
+        if (abi >= 0) {
+            int copyRet = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle,
+                    nativeLibraryDir, Build.SUPPORTED_ABIS[abi]);
+            if (copyRet != PackageManager.INSTALL_SUCCEEDED) {
+                return copyRet;
             }
-
-            return abi;
-        } finally {
-            handle.close();
         }
+
+        return abi;
     }
 
     private void killApplication(String pkgName, int appId, String reason) {
@@ -7536,7 +7560,7 @@
                         }
                         p = scanPackageLI(fullPath, flags,
                                 SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME,
-                                System.currentTimeMillis(), UserHandle.ALL);
+                                System.currentTimeMillis(), UserHandle.ALL, null);
                         if (p != null) {
                             /*
                              * TODO this seems dangerous as the package may have
@@ -7657,6 +7681,16 @@
         if (observer == null && observer2 == null) {
             throw new IllegalArgumentException("No install observer supplied");
         }
+        installPackageWithVerificationEncryptionAndAbiOverrideEtc(packageURI, observer, observer2,
+                flags, installerPackageName, verificationParams, encryptionParams, null);
+    }
+
+    @Override
+    public void installPackageWithVerificationEncryptionAndAbiOverrideEtc(Uri packageURI,
+            IPackageInstallObserver observer, IPackageInstallObserver2 observer2,
+            int flags, String installerPackageName,
+            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams,
+            String packageAbiOverride) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
                 null);
 
@@ -7696,7 +7730,8 @@
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
         msg.obj = new InstallParams(packageURI, observer, observer2, filteredFlags,
-                installerPackageName, verificationParams, encryptionParams, user);
+                installerPackageName, verificationParams, encryptionParams, user,
+                packageAbiOverride);
         mHandler.sendMessage(msg);
     }
 
@@ -8405,11 +8440,14 @@
         private int mRet;
         private File mTempPackage;
         final ContainerEncryptionParams encryptionParams;
+        final String packageAbiOverride;
+        final String packageInstructionSetOverride;
 
         InstallParams(Uri packageURI,
                 IPackageInstallObserver observer, IPackageInstallObserver2 observer2,
                 int flags, String installerPackageName, VerificationParams verificationParams,
-                ContainerEncryptionParams encryptionParams, UserHandle user) {
+                ContainerEncryptionParams encryptionParams, UserHandle user,
+                String packageAbiOverride) {
             super(user);
             this.mPackageURI = packageURI;
             this.flags = flags;
@@ -8418,6 +8456,9 @@
             this.installerPackageName = installerPackageName;
             this.verificationParams = verificationParams;
             this.encryptionParams = encryptionParams;
+            this.packageAbiOverride = packageAbiOverride;
+            this.packageInstructionSetOverride = (packageAbiOverride == null) ?
+                    packageAbiOverride : VMRuntime.getInstructionSet(packageAbiOverride);
         }
 
         @Override
@@ -8563,7 +8604,7 @@
                         // Remote call to find out default install location
                         final String packageFilePath = packageFile.getAbsolutePath();
                         pkgLite = mContainerService.getMinimalPackageInfo(packageFilePath, flags,
-                                lowThreshold);
+                                lowThreshold, packageAbiOverride);
 
                         /*
                          * If we have too little free space, try to free cache
@@ -8572,10 +8613,10 @@
                         if (pkgLite.recommendedInstallLocation
                                 == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                             final long size = mContainerService.calculateInstalledSize(
-                                    packageFilePath, isForwardLocked());
+                                    packageFilePath, isForwardLocked(), packageAbiOverride);
                             if (mInstaller.freeCache(size + lowThreshold) >= 0) {
                                 pkgLite = mContainerService.getMinimalPackageInfo(packageFilePath,
-                                        flags, lowThreshold);
+                                        flags, lowThreshold, packageAbiOverride);
                             }
                             /*
                              * The cache free must have deleted the file we
@@ -8995,11 +9036,12 @@
         final ManifestDigest manifestDigest;
         final UserHandle user;
         final String instructionSet;
+        final String abiOverride;
 
         InstallArgs(Uri packageURI,
                 IPackageInstallObserver observer, IPackageInstallObserver2 observer2,
                 int flags, String installerPackageName, ManifestDigest manifestDigest,
-                UserHandle user, String instructionSet) {
+                UserHandle user, String instructionSet, String abiOverride) {
             this.packageURI = packageURI;
             this.flags = flags;
             this.observer = observer;
@@ -9008,6 +9050,7 @@
             this.manifestDigest = manifestDigest;
             this.user = user;
             this.instructionSet = instructionSet;
+            this.abiOverride = abiOverride;
         }
 
         abstract void createCopyFile();
@@ -9063,12 +9106,13 @@
         FileInstallArgs(InstallParams params) {
             super(params.getPackageUri(), params.observer, params.observer2, params.flags,
                     params.installerPackageName, params.getManifestDigest(),
-                    params.getUser(), null /* instruction set */);
+                    params.getUser(), params.packageInstructionSetOverride,
+                    params.packageAbiOverride);
         }
 
         FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath,
                 String instructionSet) {
-            super(null, null, null, 0, null, null, null, instructionSet);
+            super(null, null, null, 0, null, null, null, instructionSet, null);
             File codeFile = new File(fullCodePath);
             installDir = codeFile.getParentFile();
             codeFileName = fullCodePath;
@@ -9077,7 +9121,7 @@
         }
 
         FileInstallArgs(Uri packageURI, String pkgName, String dataDir, String instructionSet) {
-            super(packageURI, null, null, 0, null, null, null, instructionSet);
+            super(packageURI, null, null, 0, null, null, null, instructionSet, null);
             installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir;
             String apkName = getNextCodePath(null, pkgName, ".apk");
             codeFileName = new File(installDir, apkName + ".apk").getPath();
@@ -9181,14 +9225,26 @@
                 NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryFile);
                 nativeLibraryFile.delete();
             }
+
+            final NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(codeFile);
+            String[] abiList = (abiOverride != null) ?
+                    new String[] { abiOverride } : Build.SUPPORTED_ABIS;
             try {
-                int copyRet = copyNativeLibrariesForInternalApp(codeFile, nativeLibraryFile);
+                if (Build.SUPPORTED_64_BIT_ABIS.length > 0 &&
+                        abiOverride == null &&
+                        NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
+                    abiList = Build.SUPPORTED_32_BIT_ABIS;
+                }
+
+                int copyRet = copyNativeLibrariesForInternalApp(handle, nativeLibraryFile, abiList);
                 if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
                     return copyRet;
                 }
             } catch (IOException e) {
                 Slog.e(TAG, "Copying native libraries failed", e);
                 ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+            } finally {
+                handle.close();
             }
 
             return ret;
@@ -9403,14 +9459,15 @@
         AsecInstallArgs(InstallParams params) {
             super(params.getPackageUri(), params.observer, params.observer2, params.flags,
                     params.installerPackageName, params.getManifestDigest(),
-                    params.getUser(), null /* instruction set */);
+                    params.getUser(), params.packageInstructionSetOverride,
+                    params.packageAbiOverride);
         }
 
         AsecInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath,
                 String instructionSet, boolean isExternal, boolean isForwardLocked) {
             super(null, null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0)
                     | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
-                    null, null, null, instructionSet);
+                    null, null, null, instructionSet, null);
             // Extract cid from fullCodePath
             int eidx = fullCodePath.lastIndexOf("/");
             String subStr1 = fullCodePath.substring(0, eidx);
@@ -9422,7 +9479,7 @@
         AsecInstallArgs(String cid, String instructionSet, boolean isForwardLocked) {
             super(null, null, null, (isAsecExternal(cid) ? PackageManager.INSTALL_EXTERNAL : 0)
                     | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
-                    null, null, null, instructionSet);
+                    null, null, null, instructionSet, null);
             this.cid = cid;
             setCachePath(PackageHelper.getSdDir(cid));
         }
@@ -9431,7 +9488,7 @@
                 boolean isExternal, boolean isForwardLocked) {
             super(packageURI, null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0)
                     | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
-                    null, null, null, instructionSet);
+                    null, null, null, instructionSet, null);
             this.cid = cid;
         }
 
@@ -9443,7 +9500,7 @@
             try {
                 mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI,
                         Intent.FLAG_GRANT_READ_URI_PERMISSION);
-                return imcs.checkExternalFreeStorage(packageURI, isFwdLocked());
+                return imcs.checkExternalFreeStorage(packageURI, isFwdLocked(), abiOverride);
             } finally {
                 mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION);
             }
@@ -9469,7 +9526,8 @@
                 mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI,
                         Intent.FLAG_GRANT_READ_URI_PERMISSION);
                 newCachePath = imcs.copyResourceToContainer(packageURI, cid, getEncryptKey(),
-                        RES_FILE_NAME, PUBLIC_RES_FILE_NAME, isExternal(), isFwdLocked());
+                        RES_FILE_NAME, PUBLIC_RES_FILE_NAME, isExternal(), isFwdLocked(),
+                        abiOverride);
             } finally {
                 mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION);
             }
@@ -9777,7 +9835,7 @@
      */
     private void installNewPackageLI(PackageParser.Package pkg,
             int parseFlags, int scanMode, UserHandle user,
-            String installerPackageName, PackageInstalledInfo res) {
+            String installerPackageName, PackageInstalledInfo res, String abiOverride) {
         // Remember this for later, in case we need to rollback this install
         String pkgName = pkg.packageName;
 
@@ -9805,7 +9863,7 @@
         }
         mLastScanError = PackageManager.INSTALL_SUCCEEDED;
         PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,
-                System.currentTimeMillis(), user);
+                System.currentTimeMillis(), user, abiOverride);
         if (newPackage == null) {
             Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
             if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
@@ -9832,7 +9890,7 @@
 
     private void replacePackageLI(PackageParser.Package pkg,
             int parseFlags, int scanMode, UserHandle user,
-            String installerPackageName, PackageInstalledInfo res) {
+            String installerPackageName, PackageInstalledInfo res, String abiOverride) {
 
         PackageParser.Package oldPackage;
         String pkgName = pkg.packageName;
@@ -9861,17 +9919,19 @@
         boolean sysPkg = (isSystemApp(oldPackage));
         if (sysPkg) {
             replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanMode,
-                    user, allUsers, perUserInstalled, installerPackageName, res);
+                    user, allUsers, perUserInstalled, installerPackageName, res,
+                    abiOverride);
         } else {
             replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanMode,
-                    user, allUsers, perUserInstalled, installerPackageName, res);
+                    user, allUsers, perUserInstalled, installerPackageName, res,
+                    abiOverride);
         }
     }
 
     private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
             PackageParser.Package pkg, int parseFlags, int scanMode, UserHandle user,
             int[] allUsers, boolean[] perUserInstalled,
-            String installerPackageName, PackageInstalledInfo res) {
+            String installerPackageName, PackageInstalledInfo res, String abiOverride) {
         PackageParser.Package newPackage = null;
         String pkgName = deletedPackage.packageName;
         boolean deletedPkg = true;
@@ -9896,7 +9956,7 @@
             // Successfully deleted the old package. Now proceed with re-installation
             mLastScanError = PackageManager.INSTALL_SUCCEEDED;
             newPackage = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_TIME,
-                    System.currentTimeMillis(), user);
+                    System.currentTimeMillis(), user, abiOverride);
             if (newPackage == null) {
                 Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
                 if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
@@ -9925,7 +9985,7 @@
             }
             // Since we failed to install the new package we need to restore the old
             // package that we deleted.
-            if(deletedPkg) {
+            if (deletedPkg) {
                 if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, reinstalling: " + deletedPackage);
                 File restoreFile = new File(deletedPackage.mPath);
                 // Parse old package
@@ -9936,7 +9996,7 @@
                 int oldScanMode = (oldOnSd ? 0 : SCAN_MONITOR) | SCAN_UPDATE_SIGNATURE
                         | SCAN_UPDATE_TIME;
                 if (scanPackageLI(restoreFile, oldParseFlags, oldScanMode,
-                        origUpdateTime, null) == null) {
+                        origUpdateTime, null, null) == null) {
                     Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade");
                     return;
                 }
@@ -9956,7 +10016,7 @@
     private void replaceSystemPackageLI(PackageParser.Package deletedPackage,
             PackageParser.Package pkg, int parseFlags, int scanMode, UserHandle user,
             int[] allUsers, boolean[] perUserInstalled,
-            String installerPackageName, PackageInstalledInfo res) {
+            String installerPackageName, PackageInstalledInfo res, String abiOverride) {
         if (DEBUG_INSTALL) Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
                 + ", old=" + deletedPackage);
         PackageParser.Package newPackage = null;
@@ -10010,7 +10070,7 @@
         // Successfully disabled the old package. Now proceed with re-installation
         res.returnCode = mLastScanError = PackageManager.INSTALL_SUCCEEDED;
         pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
-        newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0, user);
+        newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0, user, abiOverride);
         if (newPackage == null) {
             Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
             if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
@@ -10044,7 +10104,7 @@
                 removeInstalledPackageLI(newPackage, true);
             }
             // Add back the old system package
-            scanPackageLI(oldPkg, parseFlags, SCAN_MONITOR | SCAN_UPDATE_SIGNATURE, 0, user);
+            scanPackageLI(oldPkg, parseFlags, SCAN_MONITOR | SCAN_UPDATE_SIGNATURE, 0, user, null);
             // Restore the old system information in Settings
             synchronized(mPackages) {
                 if (updatedSettings) {
@@ -10278,10 +10338,10 @@
         pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
         if (replace) {
             replacePackageLI(pkg, parseFlags, scanMode, args.user,
-                    installerPackageName, res);
+                    installerPackageName, res, args.abiOverride);
         } else {
             installNewPackageLI(pkg, parseFlags, scanMode | SCAN_DELETE_DATA_ON_FAILURES, args.user,
-                    installerPackageName, res);
+                    installerPackageName, res, args.abiOverride);
         }
         synchronized (mPackages) {
             final PackageSetting ps = mSettings.mPackages.get(pkgName);
@@ -10698,7 +10758,7 @@
             parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
         }
         PackageParser.Package newPkg = scanPackageLI(disabledPs.codePath,
-                parseFlags, SCAN_MONITOR | SCAN_NO_PATHS, 0, null);
+                parseFlags, SCAN_MONITOR | SCAN_NO_PATHS, 0, null, null);
 
         if (newPkg == null) {
             Slog.w(TAG, "Failed to restore system package:" + newPs.name
@@ -12511,7 +12571,7 @@
                 doGc = true;
                 synchronized (mInstallLock) {
                     final PackageParser.Package pkg = scanPackageLI(new File(codePath), parseFlags,
-                            0, 0, null);
+                            0, 0, null, null);
                     // Scan the package
                     if (pkg != null) {
                         /*
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java
index 4bdd2be..34168a8 100644
--- a/services/core/java/com/android/server/tv/TvInputHal.java
+++ b/services/core/java/com/android/server/tv/TvInputHal.java
@@ -16,10 +16,10 @@
 
 package com.android.server.tv;
 
+import android.media.tv.TvInputHardwareInfo;
+import android.media.tv.TvStreamConfig;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.tv.TvInputHardwareInfo;
-import android.tv.TvStreamConfig;
 import android.view.Surface;
 
 /**
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index b95b0f0..e34f42b 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -17,12 +17,12 @@
 package com.android.server.tv;
 
 import android.content.Context;
+import android.media.tv.ITvInputHardware;
+import android.media.tv.ITvInputHardwareCallback;
+import android.media.tv.TvInputHardwareInfo;
+import android.media.tv.TvStreamConfig;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.tv.ITvInputHardware;
-import android.tv.ITvInputHardwareCallback;
-import android.tv.TvInputHardwareInfo;
-import android.tv.TvStreamConfig;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.KeyEvent;
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index e52f218..3d4e4b0 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -31,6 +31,18 @@
 import android.content.pm.ServiceInfo;
 import android.database.Cursor;
 import android.graphics.Rect;
+import android.media.tv.ITvInputClient;
+import android.media.tv.ITvInputHardware;
+import android.media.tv.ITvInputHardwareCallback;
+import android.media.tv.ITvInputManager;
+import android.media.tv.ITvInputService;
+import android.media.tv.ITvInputServiceCallback;
+import android.media.tv.ITvInputSession;
+import android.media.tv.ITvInputSessionCallback;
+import android.media.tv.TvContract;
+import android.media.tv.TvInputHardwareInfo;
+import android.media.tv.TvInputInfo;
+import android.media.tv.TvInputService;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -41,18 +53,6 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.provider.TvContract;
-import android.tv.ITvInputClient;
-import android.tv.ITvInputHardware;
-import android.tv.ITvInputHardwareCallback;
-import android.tv.ITvInputManager;
-import android.tv.ITvInputService;
-import android.tv.ITvInputServiceCallback;
-import android.tv.ITvInputSession;
-import android.tv.ITvInputSessionCallback;
-import android.tv.TvInputHardwareInfo;
-import android.tv.TvInputInfo;
-import android.tv.TvInputService;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.InputChannel;
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index f0c4f3a..afe629d 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -316,7 +316,7 @@
             (void*) nativeOpen },
     { "nativeSetSurface", "(JIILandroid/view/Surface;)I",
             (void*) nativeSetSurface },
-    { "nativeGetStreamConfigs", "(JII)[Landroid/tv/TvStreamConfig;",
+    { "nativeGetStreamConfigs", "(JII)[Landroid/media/tv/TvStreamConfig;",
             (void*) nativeGetStreamConfigs },
     { "nativeClose", "(J)V",
             (void*) nativeClose },
@@ -346,10 +346,10 @@
             gTvInputHalClassInfo.streamConfigsChanged, clazz,
             "streamConfigsChangedFromNative", "(I)V");
 
-    FIND_CLASS(gTvStreamConfigClassInfo.clazz, "android/tv/TvStreamConfig");
+    FIND_CLASS(gTvStreamConfigClassInfo.clazz, "android/media/tv/TvStreamConfig");
     gTvStreamConfigClassInfo.clazz = jclass(env->NewGlobalRef(gTvStreamConfigClassInfo.clazz));
 
-    FIND_CLASS(gTvStreamConfigBuilderClassInfo.clazz, "android/tv/TvStreamConfig$Builder");
+    FIND_CLASS(gTvStreamConfigBuilderClassInfo.clazz, "android/media/tv/TvStreamConfig$Builder");
     gTvStreamConfigBuilderClassInfo.clazz =
             jclass(env->NewGlobalRef(gTvStreamConfigBuilderClassInfo.clazz));
 
@@ -360,27 +360,27 @@
     GET_METHOD_ID(
             gTvStreamConfigBuilderClassInfo.streamId,
             gTvStreamConfigBuilderClassInfo.clazz,
-            "streamId", "(I)Landroid/tv/TvStreamConfig$Builder;");
+            "streamId", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
     GET_METHOD_ID(
             gTvStreamConfigBuilderClassInfo.type,
             gTvStreamConfigBuilderClassInfo.clazz,
-            "type", "(I)Landroid/tv/TvStreamConfig$Builder;");
+            "type", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
     GET_METHOD_ID(
             gTvStreamConfigBuilderClassInfo.maxWidth,
             gTvStreamConfigBuilderClassInfo.clazz,
-            "maxWidth", "(I)Landroid/tv/TvStreamConfig$Builder;");
+            "maxWidth", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
     GET_METHOD_ID(
             gTvStreamConfigBuilderClassInfo.maxHeight,
             gTvStreamConfigBuilderClassInfo.clazz,
-            "maxHeight", "(I)Landroid/tv/TvStreamConfig$Builder;");
+            "maxHeight", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
     GET_METHOD_ID(
             gTvStreamConfigBuilderClassInfo.generation,
             gTvStreamConfigBuilderClassInfo.clazz,
-            "generation", "(I)Landroid/tv/TvStreamConfig$Builder;");
+            "generation", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
     GET_METHOD_ID(
             gTvStreamConfigBuilderClassInfo.build,
             gTvStreamConfigBuilderClassInfo.clazz,
-            "build", "()Landroid/tv/TvStreamConfig;");
+            "build", "()Landroid/media/tv/TvStreamConfig;");
 
     return 0;
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 164fe05..18ece5b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -29,6 +29,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.media.AudioService;
+import android.media.tv.TvInputManager;
 import android.os.Build;
 import android.os.Environment;
 import android.os.FactoryTest;
@@ -43,7 +44,6 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.service.dreams.DreamService;
-import android.tv.TvInputManager;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
diff --git a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
index c7715ad..fc5426c 100644
--- a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
+++ b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
@@ -43,7 +43,6 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        HardwareRenderer.sUseRenderThread = true;
         setContentView(R.layout.activity_main);
         ListView lv = (ListView) findViewById(android.R.id.list);
         lv.setDrawSelectorOnTop(true);
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable22.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable22.xml
new file mode 100644
index 0000000..8d38cb5
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable22.xml
@@ -0,0 +1,72 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <size
+        android:height="64dp"
+        android:width="64dp" />
+
+    <viewport
+        android:viewportHeight="400"
+        android:viewportWidth="400" />
+
+    <group android:name="backgroundGroup" >
+        <path
+            android:name="background1"
+            android:fill="#80000000"
+            android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+        <path
+            android:name="background2"
+            android:fill="#80000000"
+            android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+    </group>
+    <group
+        android:name="translateToCenterGroup"
+        android:translateX="50.0"
+        android:translateY="90.0" >
+        <path
+            android:name="twoLines"
+            android:pathData="M 0,0 v 100 M 0,0 h 100"
+            android:stroke="#FFFF0000"
+            android:strokeWidth="20" />
+
+        <group
+            android:name="rotationGroup"
+            android:pivotX="0.0"
+            android:pivotY="0.0"
+            android:rotation="-45.0" >
+            <path
+                android:name="twoLines1"
+                android:pathData="M 0,0 v 100 M 0,0 h 100"
+                android:stroke="#FF00FF00"
+                android:strokeWidth="20" />
+
+            <group
+                android:name="translateGroup"
+                android:translateX="130.0"
+                android:translateY="160.0" >
+                <group android:name="scaleGroup" >
+                    <path
+                        android:name="twoLines2"
+                        android:pathData="M 0,0 v 100 M 0,0 h 100"
+                        android:stroke="#FF0000FF"
+                        android:strokeWidth="20" />
+                </group>
+            </group>
+        </group>
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable23.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable23.xml
new file mode 100644
index 0000000..52acd7a
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable23.xml
@@ -0,0 +1,86 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <size
+        android:height="64dp"
+        android:width="64dp" />
+
+    <viewport
+        android:viewportHeight="400"
+        android:viewportWidth="400" />
+
+    <group android:name="backgroundGroup" >
+        <path
+            android:name="background1"
+            android:fill="#80000000"
+            android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+        <path
+            android:name="background2"
+            android:fill="#80000000"
+            android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+    </group>
+    <group
+        android:name="translateToCenterGroup"
+        android:translateX="50.0"
+        android:translateY="90.0" >
+        <path
+            android:name="twoLines"
+            android:pathData="@string/twoLinePathData"
+            android:stroke="#FFFF0000"
+            android:strokeWidth="20" />
+
+        <group
+            android:name="rotationGroup"
+            android:pivotX="0.0"
+            android:pivotY="0.0"
+            android:rotation="-45.0" >
+            <path
+                android:name="twoLines1"
+                android:pathData="@string/twoLinePathData"
+                android:stroke="#FF00FF00"
+                android:strokeWidth="20" />
+
+            <group
+                android:name="translateGroup"
+                android:translateX="130.0"
+                android:translateY="160.0" >
+                <group android:name="scaleGroup" >
+                    <path
+                        android:name="twoLines3"
+                        android:pathData="@string/twoLinePathData"
+                        android:stroke="#FF0000FF"
+                        android:strokeWidth="20" />
+                </group>
+            </group>
+
+            <group
+                android:name="translateGroupHalf"
+                android:translateX="65.0"
+                android:translateY="80.0" >
+                <group android:name="scaleGroup" >
+                    <path
+                        android:name="twoLines2"
+                        android:pathData="@string/twoLinePathData"
+                        android:fill="?android:attr/colorForeground"
+                        android:stroke="?android:attr/colorForeground"
+                        android:strokeWidth="20" />
+                </group>
+            </group>
+        </group>
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/values/strings.xml b/tests/VectorDrawableTest/res/values/strings.xml
index 64163c2..b49a1aa 100644
--- a/tests/VectorDrawableTest/res/values/strings.xml
+++ b/tests/VectorDrawableTest/res/values/strings.xml
@@ -15,4 +15,5 @@
 -->
 
 <resources>
+    <string name="twoLinePathData" >"M 0,0 v 100 M 0,0 h 100"</string>
 </resources>
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index e0624e5..c2a5e6b 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -17,11 +17,11 @@
 import android.content.res.Resources;
 import android.graphics.drawable.VectorDrawable;
 import android.os.Bundle;
-import android.view.View;
 import android.widget.TextView;
 import android.widget.Button;
 import android.widget.GridLayout;
 import android.widget.ScrollView;
+
 import java.text.DecimalFormat;
 
 @SuppressWarnings({"UnusedDeclaration"})
@@ -48,7 +48,9 @@
             R.drawable.vector_drawable18,
             R.drawable.vector_drawable19,
             R.drawable.vector_drawable20,
-            R.drawable.vector_drawable21
+            R.drawable.vector_drawable21,
+            R.drawable.vector_drawable22,
+            R.drawable.vector_drawable23
     };
 
     @Override